EF Code First Implemented Interface Property

I have the following model.

interface IKeywordedEntity
{
    IEntityCollection<Keyword> Keywords { get; }
}
class Foo : EntityBase, IKeywordedEntity
{
     public virtual IEntityCollection<Keyword> Keywords { get { ... } }
}
class Bar : EntityBase, IKeywordedEntity
{
     public virtual IEntityCollection<Keyword> Keywords { get { ... } }
}

      

I want to write an extension method that automatically handles keywords for each one in OnModelCreating

.

public static void WithKeywords<TEntityType>(this EntityTypeConfiguration<TEntityType> 
   entityTypeConfiguration) where TEntityType : EntityBase, IKeywordedEntity
{
    entityTypeConfiguration.HasMany(e => e.Keywords).WithMany();
}

      

Therefore, I call it like this: OnModelCreating

.

modelBuilder.Entity<Foo>.WithKeywords();
modelBuilder.Entity<Bar>.WithKeywords();

      

However, I am getting the following exception:

The "Keywords" navigation property is not a declared property of type 'Foo'. Make sure it has not been explicitly excluded from the model and that it is a valid navigation property.

What can I do to make this extension method work?

+3


source to share


3 answers


After reading Ladislav's answer, I decided to write the expression by hand.



    public static void WithKeywords<TEntityType>(this EntityTypeConfiguration<TEntityType> entityTypeConfiguration)
        where TEntityType : EntityBase, IKeywordedEntity
    {
        var rootExpression = Expression.Parameter(typeof (TEntityType));
        var expression = Expression.Property(rootExpression, "Keywords");

        entityTypeConfiguration.HasMany(Expression.Lambda<Func<TEntityType, ICollection<Keyword>>>(expression, rootExpression)).WithMany();
    }

      

+2


source


After playing around with this, I think you won't. This is a limitation or bug in the EF API. In your extension method, you are not mapping Foo

, but rather IKeywordEntity

, and the display becomes corrupted. There are two problems: EF doesn't like interfaces, but even if you change your design and use an abstract class instead of an interface, it will work for simple properties, but it still won't work for navigation properties. At least this is what I get from my own experiments.



+2


source


Even though I'm not sure what exactly your line of thinking is here (I get what you need) - eg. what the EntityBase does and you have the "embedded" keywords in it
You need to make sure you draw the property somehow (and actually implement it)
I think you go to the TPC model - that means something like this ...

modelBuilder.Entity<Foo>().Map(x =>
{
  x.MapInheritedProperties();
  x.ToTable("Foo");
})

      

... MapInheritedProperties will sort the "flattened" hierarchy for a "specific" type.
You will need a base class that is abstract at least to implement properties, and Code First can choose that.
a somewhat related question ...
Entity Framework 4.1 Code First: get all entities with a specific base class
In short, I think you are better off using an abstract class for this, but you still have some work to do - generalizing things around the code firstly, the not so easy reason for many reservations. Also you need to get your inheritance model straight, which is what you need.

0


source







All Articles