如何处理EF 4.3.1设置修改了Rowversion行

时间:2012-04-27 15:36:42

标签: c# .net entity-framework entity-framework-4.3

说我们有:

public class Driver
{
    public int driverID { get; set; }
    public byte[] stamp { get; set; }
    public string name { get; set; }
    public string prename { get; set; }
}

现在简而言之,我面临着这种情况。

 ...
 var myDriver = myCustomDBContext.Drivers.AsNoTracking()
                                         .Where(d => d.driverID == driverID)
                                         .SingleOrDefault();
 ...
 myDriver.name = "John";
 myDriver.prename = "Lennon";
 ...
 myCustomDBContext.Drivers.Attach(myDriver);
 myCustomDBContext.Entry(myDriver).State = EntityState.Modified;
 myCustomDBContext.SaveChanges();
 ...

结果是

 The column cannot be modified because it is an identity, rowversion or 
     a system column. [Column name = stamp]

是否有任何方法可以强制对已分离的实体执行更新,或者此 rowversion 列的变通方法不能设置为已修改。

1 个答案:

答案 0 :(得分:7)

看起来你没有在模型中将stamp属性指定为rowversion,它只是一个二进制字段。您可以使用Fluent API指定它:

modelBuilder.Entity<Driver>().Property(d => d.stamp)
    .IsRowVersion()
    .IsConcurrencyToken(false);

上面的代码适用于您不希望将stamp属性作为并发令牌的情况。 (默认情况下,rowversion是一个并发令牌,因此您必须显式禁用它。)如果您想将它作为并发令牌,那么您可以使用Fluent API ......

modelBuilder.Entity<Driver>().Property(d => d.stamp)
    .IsRowVersion();

...或使用数据注释:

[Timestamp]
public byte[] stamp { get; set; }

这应该可以防止EF为此属性写一个UPDATE。

修改

如果使用数据库优先策略,则[Timestamp]属性不起作用。此属性仅适用于Code-First开发。

使用Database-First时,连接字符串包含引用EDMX文件中定义的EDM的元数据部分:

connectionString="metadata=res://*/Model1.csdl
                          |res://*/Model1.ssdl
                          |res://*/Model1.msl;
                          ...
                          ..."

如果Entity Framework在连接字符串中找到此部分,它不会在模型属性上使用数据注释,也不会处理Fluent API中的任何代码(OnModelCreating根本不会调用)。相反,它从嵌入和编译的EDMX文件中加载映射定义。

这意味着,如果要将stamp属性定义为并发令牌,则必须在EDMX文件中执行此操作。在XML中,它看起来像这样:

在SSDL部分:

<Property Name="stamp" Type="timestamp" Nullable="false"
          StoreGeneratedPattern="Computed" />

在CSDL部分:

<Property Name="stamp" Type="Binary" Nullable="false" MaxLength="8"
          FixedLength="true"
          annotation:StoreGeneratedPattern="Computed"
          ConcurrencyMode="Fixed" />

您也可以在Visual Studio中的模型设计器中定义它:在设计器表面中标记实体中的stamp属性,转到属性窗口并将“并发模式”设置为“固定”(以及将“StoreGeneratedPattern”设置为“Computed”)。

您还可以从连接字符串中删除元数据部分。但这实际上意味着您首先从数据库切换到代码优先开发。然后将尊重所有属性和Fluent API,但不再遵循EDMX中的任何定义。