0

I know that EF isn't supposed to support generic Entity types but I have a huge need for it in a project... I have about 200 classes containing 0 to 5 complex generic property :

public class MyCommonProperty
{
    public virtual string Key { get; set; }
}

public class MyCustomClass<T> : MyCommonProperty where T : struct, IComparable, IFormattable, IConvertible
{
    public virtual T Value { get; set; }
    public virtual string DisplayValue { get; set; }

    public MyCustomClass(string key)
    {
        Key = key;
    }
}

public class ConcreteClass
{
    public int Id { get; set; }
    public MyCustomClass<CustomType1> CustomType1 { get; set; }
    public MyCustomClass<CustomType2> CustomType2 { get; set; }
}

I just want to persist the Key property in the DB with Entity Frameworks, using these POCO. Here is my model :

  • Entity Type
    • ConcreteClass
      • Id (int, Identity)
      • CustomType1 (MyCommonProperty)
      • CustomType2 (MyCommonProperty)
  • Complex Types
    • MyCommonProperty
      • Key (string)

Finally, in my UI, the code looks like :

using (var db = new ModelContainer())
{
    db.ConcreteClassSet.AddObject(new ConcreteClass()
    {
        CustomType1 = new MyCustomClass<CustomType1>() { Key = "RandomKey1" },
        CustomType2 = new MyCustomClass<CustomType2>() { Key = "RandomKey2" }
    });
    db.SaveChanges();
}

When I run this code, I get this error :

The member with identity 'Domain.MyCustomClass`1[[Domain.CustomType1, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' does not exist in the metadata collection.

Although MyCustomClass wasn't defined in my edmx, I though EF wouldn't care about this class as a MyCustomClass is also a MyCommonProperty wich is defined in the metadata...

I overrided the ValidateEntity in my container :

public partial class ModelContainer : DbContext
{
    public ModelContainer()
        : base("name=ModelContainer")
    {
    }

    protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
        if (entityEntry.Entity is ConcreteClass)
            return new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
        return base.ValidateEntity(entityEntry, items);
    }

    public DbSet<ConcreteClass> ConcreteClassSet { get; set; }
}

Basically, I turned off the validation for my ConcreteClass, telling EF that they are always valid. With this workaround, the db.Save() works : in the database, a new row is added, with a generated Id and "RandomKey1" and "RandomKey2" in the CustomType1 and CustomType2 fields.

Now the problem is the validation : I don't want to turn off the validation for all the entities containing those generics properties It looks like the only problem is that Entity search for the concrete type (MyCustomClass) of my property in the metadata and can't find it because the only type declared there is MyCommonProperty

I think that it would be possible by modifying the metadata to add some fake types into it. For example by finding the MyCommonProperty, copying it, and rename the copy 'Domain.MyCustomClass`1[[Domain.CustomType1, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'

var metadata = (this as IObjectContextAdapter).ObjectContext.MetadataWorkspace;
var metaType = metadata.GetType("MyCommonProperty", "Domain", DataSpace.CSpace);
metaType.Name = "'Domain.MyCustomClass`1[[Domain.CustomType1, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'";
metadata.RegisterItemCollection(metaType);

I couldn't find a way to make it (lacks of knowledge and skill) so if someone have an idea or some hints, I would be grateful.

4

0 回答 0