Say we have:
public class Driver
{
public int driverID { get; set; }
public byte[] stamp { get; set; }
public string name { get; set; }
public string prename { get; set; }
}
Now in short I`m facing this kind of situation.
...
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();
...
And the result is
The column cannot be modified because it is an identity, rowversion or
a system column. [Column name = stamp]
Is there any method which could force an Update on a detached entity, or a workaround for this rowversion column not to be set as Modified.
It looks like you didn't have specified the stamp
property as a rowversion in your model and it is just a binary field. You can specify it with Fluent API:
modelBuilder.Entity<Driver>().Property(d => d.stamp)
.IsRowVersion()
.IsConcurrencyToken(false);
The code above is for the case when you don't want to have the stamp
property as a concurrency token. (A rowversion is a concurrency token by default, so you have to disable it explicitly.) If you want to have it as concurrency token, then you can use with Fluent API...
modelBuilder.Entity<Driver>().Property(d => d.stamp)
.IsRowVersion();
...or with data annotations:
[Timestamp]
public byte[] stamp { get; set; }
This should prevent EF to write an UPDATE for this property.
Edit
If you use Database-First strategy the [Timestamp]
attribute does not work. This attribute is only for Code-First development.
When you use Database-First the connection string contains a metadata section refering to the EDM defined in the EDMX file:
connectionString="metadata=res://*/Model1.csdl
|res://*/Model1.ssdl
|res://*/Model1.msl;
...
..."
If Entity Framework finds this section in the connection string it doesn't use data annotations on model properties nor does it process any code in Fluent API (OnModelCreating
isn't called at all). Instead it loads the mapping definitions from the embedded and compiled EDMX file.
That means, if you want to define the stamp
property as a concurrency token you must do this in the EDMX file. In XML it would look like this:
In SSDL section:
<Property Name="stamp" Type="timestamp" Nullable="false"
StoreGeneratedPattern="Computed" />
In CSDL section:
<Property Name="stamp" Type="Binary" Nullable="false" MaxLength="8"
FixedLength="true"
annotation:StoreGeneratedPattern="Computed"
ConcurrencyMode="Fixed" />
You can also define this in the model designer in Visual Studio: Mark the stamp
property in the entity in the designer surface, go to the Properties Window and set "Concurrency Mode" to "Fixed" (and also set the "StoreGeneratedPattern" to "Computed").
You can also remove the metadata section from the connection string. But this effectively means that you switch from database first to code first development. Then all attributes and Fluent API will be respected, but not any definitions in EDMX anymore.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With