1. ホーム
  2. .net

[解決済み] SQL Server Compact EditionデータベースのLINQ to SQLで "Row not found or changed "例外を解決するにはどうすればよいですか?

2022-12-02 21:18:42

質問

LINQ to SQL 接続でいくつかのプロパティを更新した後に DataContext に対して SubmitChanges を実行すると (SQL Server Compact Edition に対して)、"Row not found or changed." ChangeConflictException が表示されます。

var ctx = new Data.MobileServerDataDataContext(Common.DatabasePath);
var deviceSessionRecord = ctx.Sessions.First(sess => sess.SessionRecId == args.DeviceSessionId);

deviceSessionRecord.IsActive = false;
deviceSessionRecord.Disconnected = DateTime.Now;

ctx.SubmitChanges();

このクエリにより、以下のようなSQLが生成されます。

UPDATE [Sessions]
SET [Is_Active] = @p0, [Disconnected] = @p1
WHERE 0 = 1
-- @p0: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p1: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:12:02 PM]
-- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: 3.5.21022.8

明らかな問題点は WHERE 0=1 レコードが読み込まれた後、私は "deviceSessionRecord" のすべてのプロパティが主キーを含む正しいものであることを確認しました。 また、quot;ChangeConflictException"をキャッチする際に、なぜこれが失敗したかについての追加情報はありません。 この例外は、データベース内のちょうど 1 つのレコード (私が更新しようとしているレコード) でスローされることも確認しました。

奇妙なのは、コードの別のセクションに非常によく似た update ステートメントがあり、それは次の SQL を生成し、実際に私の SQL Server Compact Edition データベースを更新することです。

UPDATE [Sessions]
SET [Is_Active] = @p4, [Disconnected] = @p5
WHERE ([Session_RecId] = @p0) AND ([App_RecId] = @p1) AND ([Is_Active] = 1) AND ([Established] = @p2) AND ([Disconnected] IS NULL) AND ([Member_Id] IS NULL) AND ([Company_Id] IS NULL) AND ([Site] IS NULL) AND (NOT ([Is_Device] = 1)) AND ([Machine_Name] = @p3)
-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [0fbbee53-cf4c-4643-9045-e0a284ad131b]
-- @p1: Input Guid (Size = 0; Prec = 0; Scale = 0) [7a174954-dd18-406e-833d-8da650207d3d]
-- @p2: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:20:50 PM]
-- @p3: Input String (Size = 0; Prec = 0; Scale = 0) [CWMOBILEDEV]
-- @p4: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p5: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:20:52 PM]
-- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: 3.5.21022.8

データベーススキーマとLINQクラスを生成するDBMLの両方で、適切なプライマリフィールドの値が特定されていることを確認しました。

これはほとんど2つの部分に分かれた質問だと思います。

  1. なぜ例外がスローされるのでしょうか。
  2. 生成された 2 つ目の SQL セットを確認したところ、競合を検出するには、すべてのフィールドをチェックするのがよさそうですが、これはかなり非効率的であると想像されます。 これは常に動作する方法なのでしょうか。 主キーだけをチェックする設定はありますか?

私はこの2時間の間、これと戦ってきましたので、どんな助けでも感謝されます。

どのように解決するのですか?

厄介ですが、簡単です。

O/R-Designerのすべてのフィールドのデータ型が、SQLテーブルのデータ型と一致しているかどうかをチェックします。 nullableのダブルチェック! カラムはO/R-DesignerとSQLの両方でNullableであるか、両方でNullableでないかのどちらかである必要があります。

たとえば、NVARCHAR 列 "title" は、データベースで NULLable としてマークされ、値 NULL を含んでいます。この列が O/R マッピングで NOT NULLable とマークされていても、LINQ は正常にそれをロードし、列の文字列を NULL に設定します。

  • では、何かを変更し SubmitChanges()を呼び出します。
  • LINQ は SQL クエリを生成します。 WHERE [title] IS NULL" を含む SQL クエリを生成し、タイトルが他の誰かによって変更されていないことを確認します。
  • LINQ は、マッピングの [title] のプロパティをマッピングで検索します。
  • LINQは、[title] NOT NULLableを見つけます。
  • title] が NOT NULLable であるため、論理的には 論理上、NULLになることはない!
  • そこで、クエリを最適化するために、LINQは はこれを "where 0 = 1" に置き換えます。 SQL では "never" に相当します。

フィールドのデータ型が SQL のデータ型と一致しない場合、またはフィールドが存在しない場合、LINQ は SQL データがデータを読み込んでから変更されていないことを確認できないため、同じ症状が表示されることになります。