Hey everyone! I'm trying to implement optimistic concurrency check with the Entity Framework Code first (installed via nuget, so I assume its the last RC). However, I can't seem to make it work. I have the following class hierarchy
public abstract class DbEntityBase
{
/// <summary>
/// Autogenerated primary key for the object
/// </summary>
public Guid Id { get; private set; }
protected DbEntityBase()
{
Id = Guid.NewGuid();
}
//Some override for equality, omitted for brievity
}
public class Drawing : DbEntityBase
{
public string Name { get; set; }
//Just an implementation of ICollection<DrawingVersion>
public DrawingVersionCollection Versions { get; private set; }
public Drawing()
{
Name = "New Drawing";
Versions = new DrawingVersionCollection(this);
}
}
public class DrawingVersion : DbEntityBase
{
public string Name { get; set; }
public DateTime Started { get; set; }
public DateTime LastModified { get; set; }
public DrawingFile File { get; private set; }
public Drawing Owner { get; internal set; }
internal DrawingVersion()
{
Name = "New Version";
Started = DateTime.Now;
LastModified = DateTime.Now;
File = new DrawingFile();
}
}
I'm using the following DbContext to persists them
public class PortfolioContext : DbContext
{
public DbSet<Drawing> Drawings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Key mapping
modelBuilder.Entity<DbEntityBase>()
.HasKey(e => e.Id);
//Table Mapping
modelBuilder.Entity<DrawingVersion>().ToTable("DrawingVersion");
modelBuilder.Entity<Drawing>().ToTable("Drawing");
//Ignored fields
modelBuilder.Entity<DrawingVersion>()
.Ignore(v => v.Owner);
}
}
All this work fine and dandy. If I check the generated schema, I see to table, one for Drawing and one for for DrawingVersion. I can read, update and delete without any problems.
The problem appeared when I wanted to add a timestamp to my entities. At first I did the naive thing. I added the following in DbEntityBase
public byte[] Timestamp { get; set; }
And those line in my context
//Versionning mapping
modelBuilder.Entity<DbEntityBase>()
.Property(e => e.Timestamp)
.IsConcurrencyToken()
.HasColumnType("timestamp")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
However, during the schema generation, it fail with the following exception
System.NotSupportedException : The store generated pattern 'Computed' is not supported for properties that are not of type 'timestamp' or 'rowversion'.
The same error appear if I put the TimestampAttribute directly on my Timestamp property.
I also tried to put the timestamp data on the child classes, but then I hit the following exception
System.Data.Entity.ModelConfiguration.ModelValidationException : One or more validation errors were detected during model generation
System.Data.Edm.EdmEntityType: : Type 'Portfolio.Repositories.Drawing' is derived from the type 'Portfolio.Repositories.DbEntityBase' that is the type for EntitySet 'PortfolioContext.DbEntityBases'. Type 'Portfolio.Repositories.Drawing' defines new concurrency
requirements that are not allowed for sub types of base EntitySet types.
So I guess I can't do that either.
I must say, I am very confused. Why is the exception telling me that I should use a timestamp, as it is exactly what I am doing? Could that be a bug in the framework? If no, is their any other way to add concurrency checking with a Table PerType mapping?
I am using SQLServerCe 4 as my database along with Visual Studio 2010 SP1.