DLINQ その3
Insert、Delete、SelectしたらUpdateだろう。
ということで更新を試す。
なんか本題からそれてきてる・・・。
まぁいいか。どうせそのうち調べるんだろうから先にやっとくっていうことで。
更新するだけならエンティティを書き換えてSubmitChangesするだけなので特に問題ない。
ただ、普通更新するなら同時実行制御がいる。
ので、それを調べる。
エンティティクラスのカラムに相当するプロパティには
「Update Check」
っていうプロパティがあって、これが行のバージョン確認に使われるっぽい。
つうことはオプティミスティックロックなんだな。
・・・と思ったんだけど、この「Update Check」がデフォルトではNeverになってる。
なら、デフォルトはロックなし??え〜〜〜。
ホンマかいな、と実際に動かしてみるとちゃんと更新時にエラーがでる。
System.Data.Linq.ChangeConflictException: 行が見つからないか変更されています。 場所 System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) 場所 System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) 場所 System.Data.Linq.DataContext.SubmitChanges() 場所 ConsoleApplication4.Program.Main(String[] args) 場所 C:\Documents and Settings\xxx\My Documents\Visual Studio 2008\Projects\ConsoleApplication4\ConsoleApplication4\Program.cs:行 117
だって。
どういうこと??
調べてみると、タイムスタンプ型のカラムがあると、そこは勝手にIsVersion = true
とバージョン確認用に使うカラムですよ、とアトリビュートでマークされるみたい。
[Column(Storage = "_timestamp", AutoSync = AutoSync.Always, DbType = "rowversion NOT NULL", CanBeNull = false, IsDbGenerated = true, IsVersion = true, UpdateCheck = UpdateCheck.Never)] public System.Data.Linq.Binary timestamp
これがきいてるからUpdateCheckがNeverでも行バージョンのチェックが行われる。
タイムスタンプ型のカラムがないテーブルを追加するとデフォルトでカラムのUpdateCheckがAlwaysになってた。
なるほどー。
以下テスト。
tbl_withoutTS
id(pkey)
data
tbl_withoutTSにはタイムスタンプ型のカラムがないので、id、dataともにUpdateCheckがAlwaysになっている。
このテーブルをSelect→Updateすると次のようなSQLが出てる。
exec sp_executesql N'SELECT [t0].[id], [t0].[data] FROM [dbo].[tbl_withoutTS] AS [t0] WHERE [t0].[id] = @p0',N'@p0 int',@p0=0
これがSelectで
exec sp_executesql N'UPDATE [dbo].[tbl_withoutTS] SET [data] = @p2 WHERE ([id] = @p0) AND ([data] = @p1)',N'@p0 int,@p1 varchar(19),@p2 varchar(19)',@p0=0,@p1='2008/02/12 13:52:01',@p2='2008/02/12 13:53:36'
これがSubmitChangesしたときの更新。
tbl_withTS
id(pkey)
data
timestamp
こっちはタイムスタンプ型のカラムがある。
Selectは
exec sp_executesql N'SELECT [t0].[id], [t0].[data], [t0].[timestamp] FROM [dbo].[tbl_withTS] AS [t0] WHERE [t0].[id] = @p0',N'@p0 int',@p0=0
こんな感じで、
exec sp_executesql N'UPDATE [dbo].[tbl_withTS] SET [data] = @p2 WHERE ([id] = @p0) AND ([timestamp] = @p1) SELECT [t1].[timestamp] FROM [dbo].[tbl_withTS] AS [t1] WHERE ((@@ROWCOUNT) > 0) AND ([t1].[id] = @p3)',N'@p0 int,@p1 timestamp,@p2 varchar(19),@p3 int',@p0=0,@p1=0x0000000000000BC2,@p2='2008/02/12 14:00:33',@p3=0
更新がこれ。
タイムスタンプ型のカラムがあるときは、Updateのあとにもう一度Selectが走っている。
更新されたタイムスタンプを取得してるのかな。
テストコードはこんなの
DataClasses1DataContext dc = new DataClasses1DataContext( "Data Source=Gerbera;Initial Catalog=recordings;User ID=sa;Password=p"); var rs = from r in dc.tbl_withoutTS where r.id == 0 select r; //var rs = from r in dc.tbl_withTS // where r.id == 0 // select r; foreach (var r in rs) { Console.WriteLine("{0},{1}", r.id, r.data); r.data = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); } Console.ReadKey(); try { dc.SubmitChanges(); } catch (System.Data.Linq.ChangeConflictException e) { Console.WriteLine(e.ToString()); }
参考
http://msdn2.microsoft.com/ja-jp/library/bb399373.aspx
http://msdn2.microsoft.com/ja-jp/library/bb399389.aspx
http://msdn2.microsoft.com/ja-jp/library/bb387001.aspx
http://msdn2.microsoft.com/ja-jp/library/bb399394.aspx
さて、そろそろ本題にもどらないと・・・。