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

さて、そろそろ本題にもどらないと・・・。