说我们有:
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 列的变通方法不能设置为已修改。
答案 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中的任何定义。