1

I have several entites that are identical except for the class name that each are mapped to a corresponding identical table. The mapping for each table is similar to the following:

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

This approach works, but is repetitive.

I created this class hoping to get rid of the reposition. it is simplified here for brevity.

public class Generic<T>
{
    public Generic(DbModelBuilder modelBuilder, string tableName)
    {
        modelBuilder.Entity<T>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable(tableName);
        });
    }
}

I get the following compiler error that I do not understand:

The type 'T' must be a reference type in order to use it as parameter 'TEntityType' in the generic type or method 'System.Data.Entity.DbModelBuilder.Entity<TEntityType>()'
  • Like many .Net coders I use generics a lot but do not write them often.
  • I have use EF for a while, but I am pretty new to Code First
  • I did a lot of searching on and off of SO with no luck.
  • What am I doing wrong? What do I not understand?

Thanks in advance, Jim

3 Answers 3

4

Just add generic parameter constraint where T : class:

public class Generic<T>
   where T : class
{
    public Generic(DbModelBuilder modelBuilder, string tableName)
    {
        modelBuilder.Entity<T>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable(tableName);
        });
    }
}

Same constraint exist on DbModelBuilder.Entity<T> method, that's why you need same constraint in your generic class.

Sign up to request clarification or add additional context in comments.

Comments

3

The error states that your generic lacks a class constraint. Read here about "Constraints on Type Parameters".

So Generic<T> should be declared as

public class Generic<T> where T: class
{
    public Generic(DbModelBuilder modelBuilder, string tableName)
    {
        modelBuilder.Entity<T>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable(tableName);
        });
    }
}

But I would suggest using EntityTypeConfiguration. This class will allow you to separate entity mappings from context and implement a kind of inheritance you wanted.

For example:

public abstract class EntityConfiguration<T> : EntityTypeConfiguration<T>
    where T : Entity
{
    protected EntityConfiguration()
    {
        ToTable(typeof(T).Name);

        // All primary keys are named as <EntityName>Id
        Property(e => e.Id)
            .HasColumnName(typeof(T).Name + "Id");
    }
}

This class states that all entities will have a mapping to table which name is equal to name of the type and every table has an primary key column with name <TableName>Id.

Then mapping configuration for entity Foo could be declared as following:

public class FooConfiguration : EntityConfiguration<Foo>
{
    public FooConfiguration()
    {
        Map(m => m.MapInheritedProperties());
        // add you mapping logic here
    }
}

Then configuration should be registered in DbContext:

public class MyDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new FooConfiguration());
    }
}

1 Comment

Thank you for the great answer and the extra information. I had already marked the earlier response as the answer. But, I wanted you to know that I appreciated the additional info. I always appreciate learning something new.
0

EF provides a class that allows you to do this:

class SomeEntityMapping : EntityTypeConfiguration<SomeEntity>
{
    public SomeEntityMapping()
    {
        ToTable("My_Entity");
        HasKey(e => e.Id);
        //...
    }
} 

Then, in your DbContext, override OnModelCreating and add the Mappings to the configuration:

protected override void OnModelCreating(DbModelBuilder builder)
{
   builder.Configurations.Add(new MyEntityConfiguration());
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.