私はPostgreSQL9.1データベースに対してEntityFramework(モデルファーストアプローチ)を使用しています。
おそらく、すべてのテーブルにxminという非表示の列があり、更新を実行する前にEFが行が変更されたかどうかを判断するために使用することをご存知でしょう。
PostgreSQLの内部が変更される可能性があり、これは本番コードではまったく良い考えではないかもしれないことを私は知っていますが、試してみたいと思います。
モデルを手動で更新して1つのテーブルにこの列を含め、その動作をテストするために必要な手順は何ですか?
TIA。
編集1:これまでのところ、自己追跡エンティティでモデルファーストアプローチを使用しています。
モデルは次のように変更されました:
CSDL : <Property Name="xmin" Type="Decimal" Nullable="false" Precision="15" Scale="0" ConcurrencyMode="Fixed" />
SSDL : <Property Name="xmin" Type="numeric" Nullable="false" Precision="15" Scale="0" StoreGeneratedPattern="Computed" />
xmin列はSELECTで効果的に取得され、UPDATE中に使用されます。
UPDATE "schema"."mytable" SET "column1"=FALSE WHERE ("pk"=cast(7526 as numeric)) AND ("xmin"=cast(1185877 as numeric))
ここでの問題は、xmin列で使用されるキャストにあります。失敗します。私がこれまでに見つけたのは、キャストがまったくなくても機能するということです。しかし、この列のクエリでキャストをまったく使用しないようにEFに指示する方法がわかりません。
ところで、xmin列のデータ型は「xid」であり、NpgsqlADO.NETプロバイダーには不明です。
編集2:これはSQLテキストを生成するプロバイダーです。プロバイダーコードを調べた後、整数データ型を使用する場合、キャストがないことを確認できます。そのため、エンティティで整数を使用して値を格納し、エンティティを選択して更新しようとしました。同時実行例外で失敗します。
System.Data.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
pgsqlログは次のとおりです。
CEST LOG: instruction : BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
CEST LOG: instruction : UPDATE "schema"."mytable" SET "column1"=TRUE WHERE ("pk"=cast(7526 as numeric)) AND ("xmin"=1185882)
CEST LOG: instruction : ROLLBACK
うーん、影響を受けた行の取得に問題がある可能性があります。同じクエリを手動で実行すると、1つの行が更新されるためです...
編集3:npgsqlデバッグログを有効にしました。xminが変更されていない場合、次のようになります(UPDATE 1):
7/2/2012 12:00:38 PM 12380 Debug Entering NpgsqlState.ProcessBackendResponses()
7/2/2012 12:00:38 PM 12380 Debug Entering PGUtil.ReadString()
7/2/2012 12:00:38 PM 12380 Debug Get NpgsqlEventLog.LogLevel
7/2/2012 12:00:38 PM 12380 Debug String read: UPDATE 1.
それが変更されたとき、私は次のようになります(UPDATE 0):
7/2/2012 1:50:06 PM 12700 Debug Entering NpgsqlState.ProcessBackendResponses()
7/2/2012 1:50:06 PM 12700 Debug Entering PGUtil.ReadString()
7/2/2012 1:50:06 PM 12700 Debug Get NpgsqlEventLog.LogLevel
7/2/2012 1:50:06 PM 12700 Debug String read: UPDATE 0.
しかし、残念ながら、どちらの場合もOptimisticConcurrencyExceptionが発生します...
編集4:npgsqlログを確認した後、エンティティFrameworkは内部でDbCommand.ExecuteReader(CommandBehavior.SequentialAccess)とそれに続くreader.Read()を使用して、UPDATEステートメントの影響を受けた行数を判別しているようです。
私は間違っているかもしれませんが、問題の原因である可能性があるForwardsOnlyDataReader.Read()中にプロバイダーがfalseを返しています。
編集5:これは間違いなくプロバイダーの問題です(バージョン2.0.11.93および今後のバージョン2.0.11.94)。
INSERTステートメントの場合、プロバイダーは、基になるデータ型がSERIAL(int)またはBIGSERIAL(bigint)の場合にのみ計算列をサポートします。
UPDATEステートメントの場合、プロバイダーは特定のDbUpdateCommandTreeのReturningプロパティを処理しません。これは、計算列が返されないことを意味します。SaveChanges()を呼び出した後、エンティティオブジェクトを手動で更新する必要があります。楽観的並行性はこれまでサポートされていません。
プロバイダーに最小限のサポートを実装し、投稿を続けます。
編集6:Returningプロパティは、私自身のバージョンのプロバイダーで処理されるようになりました。コードを共有させていただきます。お気軽にお問い合わせください。