locked
How to implement Concurrency in EF code first while using a TPT hierarchy RRS feed

  • Question

  • 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.

    Saturday, April 9, 2011 2:50 AM

Answers

  • Hello,

    I think the question was answered here. The problem is that this is not TPT but TPC and you must call Map(m => m.MapInheritedProperties()) in derived entities mapping.

    Best regards,
    Ladislav

    • Proposed as answer by Jackie-Sun Thursday, April 14, 2011 9:45 AM
    • Marked as answer by Jackie-Sun Wednesday, April 20, 2011 5:35 AM
    Monday, April 11, 2011 7:08 AM