The dawn of modern programmers

現代プログラマーの朝焼け

LINQ to SQL Beta 2 to RTM #1

RTMのインストールが完了したのでLINQ to SQL での変更点について確認した結果を記録しておきます。

詳細についてはMSDNで配布されている以下の資料を参照してください。
LINQ to SQL Beta 2 to RTM Breaking Changes

Table.Attach() メソッドで detach されていないエンティティを指定すると例外がスローされる

Beta 2 ではパスしていた以下のテストコードが RTM では エラー になりました。これは NotSupportedException がスローされるようになったためです。

[Test]
public void Attachで別のDataContextで取得したエンティティの変更をDBに送信できる()
{
    InsertTestCustomer();
    NorthwindDataContext otherContext = new NorthwindDataContext();
    Customer customer = otherContext.Customers.Single(c => c.CustomerID == "ARCWY");
    
    NorthwindDataContext context = new NorthwindDataContext();
    context.Customers.Attach(customer);
    customer.ContactName = "Osaka Office";
    Assert.That(customer, Is.SameAs(context.GetChangeSet().Updates[0]));
    context.SubmitChanges();
    DeleteTestCustomer();
}

というわけでまずはテストを修正して例外スローを確認します。

[Test]
[ExpectedException(typeof(NotSupportedException))]
public void トラキングが有効な状態で別のDataContextにAttachすると例外がスローされるべき()
{
    InsertTestCustomer();
    NorthwindDataContext otherContext = new NorthwindDataContext();
    Customer customer = otherContext.Customers.Single(c => c.CustomerID == "ARCWY");

    NorthwindDataContext context = new NorthwindDataContext();
    try
    {
        context.Customers.Attach(customer);
    }
    finally
    {
        DeleteTestCustomer();
    }
}

次に Attach が成功するテストを考えましたがこれが問題です。
dettach ってなんやねん?です。
Table.Detach() メソッドはないし、Dispose も null 代入もダメでした。
苦肉の策が DataContext.ObjectTrackingEnabled を false に指定する方法です。

テストコードは以下のようになります。

[Test]
public void トラッキングを無効にすればAttachで別のDataContextで取得したエンティティの変更をDBに送信できる()
{
    InsertTestCustomer();
    NorthwindDataContext otherContext = new NorthwindDataContext() { ObjectTrackingEnabled = false };
    Customer customer = otherContext.Customers.Single(c => c.CustomerID == "ARCWY");
      
    NorthwindDataContext context = new NorthwindDataContext();
    context_.Customers.Attach(customer);
    customer.ContactName = "Osaka Office";
    Assert.That(customer, Is.SameAs(context.GetChangeSet().Updates[0]));
    context.SubmitChanges();
    DeleteTestCustomer();
}

SQL Server Profiler で確認した実行SQLの結果は以下の通りです。
無事に更新も実行できています。

exec sp_executesql N'UPDATE [dbo].[Customers]
SET [ContactName] = @p2
WHERE ([CustomerID] = @p0) AND ([CompanyName] = @p1) AND ([ContactName] IS NULL) AND ([ContactTitle] IS NULL) AND ([Address] IS NULL) AND ([City] IS NULL) AND ([Region] IS NULL) AND ([PostalCode] IS NULL) AND ([Country] IS NULL) AND ([Phone] IS NULL) AND ([Fax] IS NULL)',N'@p0 nchar(5),@p1 nvarchar(12),@p2 nvarchar(12)',@p0=N'ARCWY',@p1=N'Archway Inc.',@p2=N'Osaka Office'

未だ dettach について理解できていないのでもうしばらく調査が必要です。

ただ、N層アプリケーションでAttachを使用する局面では更新元データは基本トラッキングをオフにしておくのもよいかと考えています。(当然オフにした方がパフォーマンスがよいので)