4

我正在针对 PostgreSQL 9.1 数据库使用实体框架(模型优先方法)。

您可能都知道每个表都有一个名为xmin的隐藏列,我将使用它来帮助 EF 在执行更新之前确定该行是否已更改。

我知道 PostgreSQL 的内部结构可能会发生变化,这对于生产代码来说可能根本不是一个好主意,但我想尝试一下。

手动更新模型以在一个表中包含此列并测试其行为所需的步骤是什么?

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 列数据类型是Npgsql ADO.NET 提供程序未知的“xid” 。

编辑 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

嗯,检索受影响的行可能存在问题,因为如果手动执行相同的查询,我会更新一行...

编辑 3:我启用了 npgsql 调试日志。当 xmin 没有改变时,我有以下(更新 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 日志后,似乎实体框架在内部使用 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 属性现在在我自己的提供程序版本中处理。我很乐意分享我的代码。不要犹豫,问。

4

1 回答 1

2

xmin不太可能很快消失,并且可以用于实现一种简单形式的乐观并发控制更新。请注意,它在内部是一个无符号的32 位数字,因此不要尝试将其存储在有符号的 32 位字段中,否则它可能会工作一段时间然后坏掉。

只要您将其映射到适当的数据类型,预先阅读,将其包含在WHERE您的子句中UPDATE并在“未找到”条件下采取适当的措施,这非常简单。

于 2012-06-30T18:01:12.960 回答