开发者

Multiple Inheritance issue with EF 4.1

I am not sure what I am doing wrong here, but I am having an issue with multiple inheritance and building my model. I get the error "The property 'Id' is not a declared property on type...". Everything worked fine before I added the ContextEntity class and I had a TPC model. Each (non abstract)derived entity had it's own ID and own table. The other classes always existed and my mappings worked fine. Here are my classes:

public abstract class Entity
    {
        public virtual Guid Id { get; set; } 
        public DateTime DateCreated { get; set; }
        public DateTime DateModified { get; set; }
        public EntityStatus EntityStatus { get; set; }
        public byte[] RowVersion { get; set; }
    }


    public abstract class ContextEntity : Entity
    {
        public string Description { get; set; }
        public ICollection<Comment> Comments { get; set; }
        public virtual Contact Owner { get; set; }
    }


    public abstract class Document : ContextEntity
    {

        public virtual Subscription Subscription { get; set; }

    }

    //This is the Class I want as a table
    public class Rfi : Document
    {
        public string Number { get; set; }
        public string Subject { get; set; }

    }

Before I had the ContextEntity I only had Entity. Not all my entities will use the ContextEntity. I have this mapping file:

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
    where TEntity : Entity
    {
        protected EntityConfiguration()
        {
            HasKey(e => e.Id);

            Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(e => e.RowVersion).IsRowVersion();
        }
    }

When I just had t开发者_如何学运维he Entity base type it worked great. So I thought I would add another configuration mapper like this:

public class ContextEntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
        where TEntity : ContextEntity
    {
        protected BridgeEntityConfiguration()
        {

            HasKey(e => e.Id);

            Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(e => e.RowVersion).IsRowVersion();
            HasMany(e => e.Comments).WithMany().Map(m =>
                                                        {
                                                            m.MapLeftKey("CommentId");
                                                            m.MapRightKey("EntityId");
                                                            m.ToTable("Entity_Comments");
                                                        });
            HasMany(e => e.Attachments).WithMany().Map(m =>
                                                           {
                                                               m.MapLeftKey("AttachmentId");
                                                               m.MapRightKey("EntityId");
                                                               m.ToTable("Entity_Attachments");
                                                           });
        }
    }

My Derive mapping class looks like this:

RfiMapping: ContextEntityConfiguration<Rfi>

I am guessing EF doesn't know what to do with all the nested base classes?


You cannot derive RfiMapping from ContextEntityConfiguration<Rfi>. This would mean that you are trying to configure - for example - the Id property on your Rfi class. When added to the model configurations it basically reads like this:

modelBuilder.Entity<Rfi>()
    .HasKey(r => r.Id);
// etc.

But Id is declared on the base class Entity, so you cannot define mappings for such a property on your derived entity. That's what the exception says.

If you want to define mappings on base class properties you must also use this class in your mapping configuration:

modelBuilder.Entity<Entity>()
    .HasKey(r => r.Id);
// etc.

I believe that a generic configuration derived from EntityTypeConfiguration<TEntity> is a bad idea. The derived configuration classes should always deal with one specific entity (can also be an abstract entity) and define the mappings for it.

So, you should have the following configurations:

public class EntityConfiguration : EntityTypeConfiguration<Entity>
public class ContextEntityConfiguration : EntityTypeConfiguration<ContextEntity>
public class DocumentConfiguration : EntityTypeConfiguration<Document>
public class RfiConfiguration : EntityTypeConfiguration<Rfi>

Edit

Here is an example application that shows that it also cannot work with your old mapping (without ContextEntity). You can test and compare with the differences to your real model. There must be some important difference because you say that your old model works. I have omitted a few scalar properties to make the example simpler.

  • Create new .NET 4 console application in VS2010
  • Add reference to EntityFramework.dll
  • Delete content of Program.cs and paste in the following
  • Run application (it will crash)

->

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;

namespace EFWrongMapping
{
    public abstract class Entity
    {
        public virtual Guid Id { get; set; }
        public DateTime DateCreated { get; set; }
        public DateTime DateModified { get; set; }
    }

    public abstract class Document : Entity
    {
        public string Name { get; set; }
    }

    public class Rfi : Document
    {
        public string Number { get; set; }
        public string Subject { get; set; }
    }

    public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
        where TEntity : Entity
    {
        protected EntityConfiguration()
        {
            // The following is not allowed if TEntity is Rfi or generally any other
            // type than Entity (which makes it useless to create a generic configuration)
            HasKey(e => e.Id);
            Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }

    public class RfiMapping : EntityConfiguration<Rfi>
    {
        public RfiMapping()
        {
        }
    }

    public class MyContext : DbContext
    {
        public DbSet<Entity> Entities { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new RfiMapping());
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new MyContext())
            {
                // just try to build model and initialize DB
                var initializer = new DropCreateDatabaseIfModelChanges<MyContext>();
                try
                {
                    initializer.InitializeDatabase(context);
                }
                catch (Exception e)
                {
                    // We will land here with exception:
                    // "The property 'Id' is not a declared property on type 'Rfi'"
                    throw;
                }
            }
        }
    }
}


The issue was with the Subscription property in my Document class. In that class was a property that needed to be null-able. Once I added the mapping for the Subscription class and updated the null able property everything worked fine. Not sure why it was giving me an error on my Rfi class, but the issue was not in that class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜