ここでは、LINQ を実装するときに発生する可能性のある一般的な問題の対処法について説明します。
その他の問題については、「トラブルシューティング」をご覧ください。
接続できない
データベースに接続できません。
接続文字列が正しいこと、および SQL Server のインスタンスが実行中であることを確認してください。 また、LINQ to SQL では、名前付きパイプ プロトコルを有効にする必要があります。 詳しくは、「チュートリアルによる学習」をご覧ください。
データベースの変更内容が失われる
データベース内のデータを変更しましたが、アプリケーションを再実行すると、変更が元に戻っています。
変更結果をデータベースに保存するために、必ず SubmitChanges を呼び出してください。
データベース接続: どれほどの時間開いているか
データベース接続が開いている時間は、どれほどですか。
通常、接続は、クエリ結果を処理するまでは開いた状態を保ちます。 すべての結果を処理するのに時間がかかる可能性がある場合、結果をキャッシュに入れることが可能であれば、クエリに対して ToList を適用してください。 通常のシナリオでは、各オブジェクトが一度だけ処理されるため、DataReader
と LINQ to SQL のどちらの場合もストリーミング モデルがより優れています。
接続が厳密にどのように使用されるかは、以下に応じて異なります。
接続オブジェクトを使って DataContext が作成されている場合は、接続状態。
接続文字列の設定 (たとえば、複数のアクティブな結果セット (MARS) の有効化)。 詳細については、「 複数のアクティブな結果セット (MARS)」を参照してください。
クエリを使用しない更新
データベースに対してあらかじめクエリを実行せずに、テーブル データを更新できますか?
LINQ to SQL にはセットベースの更新コマンドはありませんが、次のいずれかの技法を使用すると、あらかじめクエリを実行せずに更新できます。
ExecuteCommand を使って SQL コードを送信する。
オブジェクトの新しいインスタンスを作成し、更新に関連したすべての現在値 (フィールド) を初期化する。 その後、DataContext を使ってオブジェクトを Attach に関連付け、更新対象のフィールドを変更します。
予期しないクエリ結果
予期しない結果がクエリから返されます。 どうなっているのか調べる方法はありますか。
予期しないストアド プロシージャ結果
戻り値が "MAX()" によって計算されるストアド プロシージャがあります。 このストアド プロシージャを O/R デザイナーのサーフェイスにドラッグすると、戻り値が正しくありません。
LINQ to SQL には、ストアド プロシージャを介して、データベースによって生成される値を返す方法が 2 つあります。
出力結果に名前を付ける。
出力パラメーターを明示的に指定する。
間違っている出力例を以下に示します。 LINQ to SQL は結果をマップできないため、常に 0 が返されます。
create procedure proc2
as
begin
select max(i) from t where name like 'hello'
end
出力パラメーターを使用して正しい出力をする例を次に示します。
create procedure proc2
@result int OUTPUT
as
select @result = MAX(i) from t where name like 'hello'
go
出力結果に名前を付けて正しい出力をする例を次に示します。
create procedure proc2
as
begin
select nax(i) AS MaxResult from t where name like 'hello'
end
詳しくは、「ストアド プロシージャによる操作のカスタマイズ」をご覧ください。
シリアル化のエラー
シリアル化を試みると、次のエラーが発生します: "アセンブリ ... の型 'System.Data.Linq.ChangeTracker+StandardChangeTracker' はシリアル化可能として設定されていません。"
LINQ to SQL のコード生成では、DataContractSerializer シリアル化がサポートされます。 XmlSerializer および BinaryFormatter はサポートされません。 詳細については、「Serialization」 (シリアル化) を参照してください。
複数の DBML ファイル
いくつかのテーブルを共有する複数の DBML ファイルが存在する場合は、コンパイラ エラーが発生します。
オブジェクト リレーショナル デザイナーで、 [コンテキストの名前空間] プロパティと [エンティティの名前空間] プロパティに、DBML ファイルごとに個別の値を設定します。 この手法により、名前および名前空間の競合を防ぐことができます。
挿入または更新で、データベース生成値を明示的に設定しなくても良いようにする
あるデータベース テーブルに "DateCreated" という列があり、その既定値は SQL "Getdate()" です。 LINQ to SQL を使用して新しいレコードを挿入しようとすると、値が "NULL" に設定されます。 データベースの既定値が設定されるようにするには、どうしたらいいですか。
ID 列 (自動インクリメント)、rowguidcol 列 (データベースが生成した GUID)、およびタイムスタンプ列の場合は、LINQ to SQL が、このような状況に自動的に対処します。 それ以外の場合には、IsDbGenerated=true
および AutoSync=Always/OnInsert/OnUpdate プロパティを手動で設定する必要があります。
複数の DataLoadOptions
最初の読み込みオプションを上書きせずに、追加の読み込みオプションを指定できますか?
はい。 次の例のように、最初のオプションは上書きされません。
Dim dlo As New DataLoadOptions()
dlo.LoadWith(Of Order)(Function(o As Order) o.Customer)
dlo.LoadWith(Of Order)(Function(o As Order) o.OrderDetails)
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Order>(o => o.Customer);
dlo.LoadWith<Order>(o => o.OrderDetails);
SQL Compact 3.5 の使用に関するエラー
テーブルを SQL Server Compact 3.5 データベースからドラッグすると、エラーが発生します。
オブジェクト リレーショナル デザイナーでは SQL Server Compact 3.5 はサポートされていませんが、LINQ to SQL ランタイムではサポートされています。 この場合、独自のエンティティ クラスを作成して適切な属性を追加する必要があります。
継承関係でのエラー
オブジェクト リレーショナル デザイナーでツールボックスの継承図形を使って、2 つのエンティティを接続すると、エラーが発生します。
関係を作成するだけでは不十分です。 識別子の列、基本クラスの識別子の値、派生クラスの識別子の値などの情報を提供する必要があります。
プロバイダー モデル
パブリック プロバイダー モデルを利用できますか?
いいえ。使用可能なパブリック プロバイダー モデルはありません。 現時点では、LINQ to SQL では SQL Server と SQL Server Compact 3.5 のみがサポートされています。
SQL 注入攻撃
LINQ to SQL は、SQL 注入攻撃からどのように保護されますか?
ユーザー入力の連結により形成される従来の SQL クエリでは、SQL 注入が大きなリスクでした。 LINQ to SQL では、クエリで SqlParameter を使用することにより、そのような注入を防止します。 ユーザー入力はパラメーター値に変換されます。 この手法は、顧客の入力で悪意のあるコマンドが使用されることを防止します。
DBML ファイル内の読み取り専用フラグの変更
DBML ファイルからオブジェクト モデルを作成するときに、どうすれば、特定のプロパティから setter を取り除くことができますか?
これは高度なシナリオですが、以下の手順に従ってください。
.dbml ファイル内で、IsReadOnly フラグを
True
に変更することにより、プロパティを変更します。部分クラスを追加します。 読み取り専用メンバー用のパラメーターを使ってコンストラクターを作成します。
既定の UpdateCheck 値 (Never) がアプリケーションにとって適切な値かどうかを検討します。
注意事項
Visual Studio でオブジェクト リレーショナル デザイナーを使用している場合は、変更内容が上書きされる可能性があります。
APTCA
System.Data.Linq は、部分的に信頼されているコードが使用できるようにマークされていますか?
はい。System.Data.Linq.dll アセンブリは、AllowPartiallyTrustedCallersAttribute 属性でマークされている .NET Framework アセンブリの 1 つです。 このマークがないと、.NET Framework のアセンブリは完全に信頼されたコードによってのみ使用されます。
部分的に信頼される呼び出し元を許可する LINQ to SQL での主なシナリオは、"信頼" の構成が中のときに、Web アプリケーションから LINQ to SQL アセンブリにアクセスできるようにする場合です。
複数のテーブルからのデータのマッピング
エンティティに、複数のテーブルから取得されたデータが含まれています。 どのようにマップできますか?
データベース内にビューを作成して、エンティティをそのビューにマップすることができます。 LINQ to SQL は、テーブル用と同じ SQL をビュー用に生成します。
Note
このシナリオでのビューの使用には、制限があります。 この手法は、Table<TEntity> に対して実行される操作が、基になるビューでサポートされるような場合に、最も安全に機能します。 どのような操作が意図されるかは、開発者だけが知っています。 たとえば、ほとんどのアプリケーションは読み取り専用です。他の多くのアプリケーションでは、ビューに対してストアド プロシージャを使用することによってのみ、Create
/Update
/Delete
操作が実行されます。
接続のプール
DataContext プールで役立つコンストラクトはありますか?
DataContext のインスタンスは再使用しないようにしてください。 DataContext はそれぞれ、特定の 1 つの編集/クエリ セッション用の状態 (ID キャッシュを含む) を保持します。 データベースの現在の状態に基づく新しいインスタンスを得るには、新しい DataContext を使用してください。
それでも、基になる ADO.NET 接続プールは使用できます。 詳しくは、「SQL Server の接続プール (ADO.NET)」をご覧ください。
2 番目の DataContext が更新されない
データベースに値を格納するために、DataContext のインスタンスを 1 つ使用しました。 しかし、2 番目の DataContext では、同じデータベースに対する値の更新が反映されません。 2 番目の DataContext インスタンスは、キャッシュされた値を返すようです。
この動作は仕様です。 LINQ to SQL は、最初のインスタンスと同じインスタンス/値を返し続けます。 更新の際には、オプティミスティック コンカレンシーが使用されます。 元のデータを使ってデータベースの現在の状態を検査し、実際に未変更であることをアサートします。 変更されている場合は競合が発生するため、アプリケーションでそれを解決する必要があります。 1 つのオプションとして、アプリケーションは、元の状態をデータベースの現在の状態にリセットして、更新を再試行できます。 詳細については、「方法: 変更の競合を管理する」を参照してください。
また、ObjectTrackingEnabled を false に設定することもできます。この場合、キャッシュと変更追跡が無効になります。 その後は、クエリを実行するたびに最新の値を取得できます。
読み取り専用モードで SubmitChanges を呼び出すことができない
読み取り専用モードで SubmitChanges を呼び出そうとすると、エラーが発生します。
読み取り専用モードでは、変更を追跡するコンテキスト機能は無効です。