ASP.NET 3.5コアプログラミング学習ノート(23):Linq-to-SQLデータの更新、トランザクション、ストレージプロセス、関数

19633 ワード

エンティティ・オブジェクトがメモリにロードされると、新しい受注を挿入する作業は簡単です.Orderクラスのインスタンスを作成し、顧客オブジェクトのOrdersセットに追加することにほかならません.Linq-to-SQLは、データコンテキスト内の変更を追跡し、データコンテキストオブジェクトのSubmitChangesを呼び出すと、それらの変更をデータベースに返します.次の例では、データを変更するプロセスを示します.

  
    
string id = " ALFKI " ;
Customer c
= dataContext.Customers.SingleOrDefault(c => c.CustomerID == id);
if (c != null )
{
//
c.Address = " 123 Flowers Streat);
//
dataContext.SubmitChanges();
}

オブジェクトの追加と削除
データコンテキストオブジェクトは、コンテキストに追加されたオブジェクトを自動的に追跡し、更新、削除、または追加されたオブジェクトを追跡します.SubmitChangesメソッドを呼び出すと、データコンテキストクラスが示され、最下位のデータベースに対して保留中の変更が更新文に変換されます.
新規レコードの追加例:

  
    
Customer customer = new Customer();
customer.CustomerID
= " KOEN2 " ;
customer.CompanyName
= " ... " ;
...
dataContext.Customers.InsertOnSubmit(customer);
dataContext.SubmitChanges();

削除例:

  
    
Customer koen2 = dataContext.Customers.SingleOrDefault(c => c.CustomerID == " KOEN2 " );
if (koen2 != null )
{
dataContext.Customers.DeleteOnSubmit(koen2);
dataContext.SubmitChanges();
}

SubmitChangesが正常に実行されると、削除されたオブジェクトは、内部キャッシュから実際に削除されることなく、データコンテキストでDeletedとしてマークされます.
クロステーブル更新
Linq-to-SQLは、データコンテキストでテーブル間関係をモデリングしたり、テーブル間更新をサポートしたりすることができます.対応するTableオブジェクトからオブジェクトを除去するだけで、残りの作業はSubmitChangesで完了します.

  
    
//
Customer mands = new Customer();
// mands
...
dataContext.Customers.InsertOnSubmit(mands);

//
Order order = new Order();
// order
...
// mands Orders
mands.Orders.Add(order);

//
dataContext.SubmitChanges();

上記の例で追加した顧客と注文を削除します.

  
    
//
var orders = from o in dataContext.Orders
where o.CustomerID == " MANDS "
select o;

//
foreach (var o in orders)
dataContext.Orders.DeleteOnSubmit(o);

//
Customer mands = dataContext.Customers.SingleOrDefault(c => c.CustomerID == " MANDS " );
if (mands != null )
{
//
dataContext.Customers.DeleteOnSubmit(mands);
dataContext.SubmitChanges();
}

まず、お客様の注文を削除してから、お客様を削除する必要があります.顧客を先に削除すると、顧客テーブルと受注テーブルにテーブル間制約があるため、例外が発生します.
オープンコンカレント
上記の例では、注文を削除するときにSQL Profileツールを使用してSQLが実際に実行した文を追跡すると、次の文が実行されていることがわかります.

  
    
Delete From dbo.Customers
Where CustomerID = ' MANDS '
and CompanyName = ' Managed Design '
and ContactName = ' Dino '
and ContactTitle is NULL
and Address = ' Via dei Tigli '
and City = ' Milan '
and Region is NULL
and PostalCode is NULL
and Country = ' Italy '
and Phone is NULL
and Fax is NULL

このテクノロジーは、レコードの更新と削除の前に、他のトランザクションがレコードを変更したかどうかを検出する「オープン・コンカレント」と呼ばれます.保守的同時実行は、更新または削除時に競合を回避するためにレコードにロックをかけます.デフォルトでは、Linq-to-SQLはオープンコンカレントを使用します.
競合例外を無視して実行を続行するパラメータをSubmitChangesに渡すことができます.

  
    
dataContext.SubmitChanges(ConflictMode.ContinueOnConflict);

デフォルトはConflictModeです.FailOnFirstConflict.更新を続行する場合、どのコマンドが失敗したかを知るにはどうすればいいですか?
このため、データコンテキストのChangeConflictsコレクションを巡回できます.

  
    
try
{
dataContext.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e)
{
foreach (ObjectChangeConflict occ in dataContext.ChangeConflicts)
{}
}

ObjectChangeConflictクラスで定義されたプロパティを使用すると、何が起こったのか、どのテーブルで発生したのか、どのエンティティオブジェクトが関連しているのかを知ることができます.
操作のカスタマイズの更新
お客様のすべての注文を削除するには、LINQを使用しない場合は、次のようにします.

  
    
Delete From orders Where customerid = ' MANDS '

Linq-to-SQLは、エンティティオブジェクトの更新操作の実装を変更する方法を提供します.Linq-to-SQLは分部クラス上に構築されているため,分部メソッドを1つ追加すればよい.
次に、Customerエンティティのデータコンテキストクラスを示します.リストは、分割メソッドで拡張できます.

  
    
partial void InsertCustomer(Customer instance);
partial
void UpdateCustomer(Customer instance);
partial void DeleteCustomer(Customer instance);

このようなメソッドの形式は、InsertXxx、UpdateXxx、DeleteXxxであり、Xxxはデータコンテキスト内のエンティティの名前を表します.これにより、お客様のレコードを削除するときに、次のことができます.

  
    
partial void DeleteCustomer(Customer instance)
{
this .ExecuteCommand( " Delete From customers Where customerid={0} " , instance.CustomerID);
}

この拡張メソッドを使用すると、顧客レコードの削除時に関連する受注が自動的に削除されます.
また、更新操作のカスタムプロパティを使用して、T-SQLコマンドの代わりにストレージ・プロシージャを使用してデータベース操作を実行することもできます.
トランザクションの使用
SubmitChangesによってコミットされたすべての更新は、1つのトランザクションで行われます.このメソッドを呼び出すと、Linq-to-SQLは現在の呼び出しが他のトランザクションの役割範囲にあるかどうかを検証し、ユーザーが開始したトランザクションがデータコンテキストに明示的にバインドされていないことを確認します.既存のトランザクションがない場合、Linq-to-SQLはローカルトランザクションを開始し、そのトランザクションを使用してすべてのT-SQLコマンドを実行します.すべてのコマンドが実行されると、Linq-to-SQLはトランザクションをコミットします.
TranscationScopeオブジェクトを使用して、SubmitChangesメソッドによって開始されたデータベース操作を独自のコードでカプセル化できます.例えば、外部のTranscationScopeオブジェクトを介して、他の非データベースリソースをトランザクションに導入したり、MSMQにメッセージを送信したり、ファイルシステムを更新したりすることができます.SubmitChangesが既存のトランザクションの役割ドメイン内にあることを検出すると、新しいトランザクションの作成だけでなく、接続のクローズも回避されます.
また、複数のSubmitChangesのコマンドをトランザクションに関連付けるトランザクションを独自に開始することもできます.このため、データコンテキストオブジェクトのTransactionプロパティを使用できます.コミットまたはロールバックは、開発者によって完全に異なります.トランザクションの接続文字列がデータコンテキストで使用されているものと一致しない場合、例外が放出されます.
ストレージ・プロシージャの使用
ストレージ・プロシージャは、ExecuteCommandメソッドを使用して、ブランチ・メソッドで実行できます.例:

  
    
partial void DeleteCustomer(Customer instance)
{
this .ExecuteCommand( " exec delete_customer {0} " , instance.CustomerID);
}

さらに、VS 2008のO/Rデザイナでストレージ・プロシージャをデータ・コンテキストに追加することで、ストレージ・プロシージャをデータ・コンテキストのメソッドとして呼び出すことができます.
CustOrderHistという名前のストレージ・プロシージャをデータ・コンテキストに追加したとします.呼び出し方法は次のとおりです.

  
    
var orders = dataContext.CustOrderHist(customerID);

varキーワードを使用して結果タイプを推定できます.ストレージ・プロシージャが複数の値または異なるタイプの値を返すと、データ・コンテキスト内のストレージ・プロシージャのカプセル化は、IMultipleResultsタイプを返します.この場合、GetResultを使用して、所与の結果にアクセスできます.ここで、Tは、特定の結果のタイプを指定するために使用される.
ユーザー定義関数の使用
ストレージ・プロシージャと同様に、データベース内のユーザーのカスタム関数をデータ・コンテキストに追加し、ページでメソッドとして呼び出すこともできます.