【问题标题】:Cannot create EF code first mapping class using generics无法使用泛型创建 EF 代码优先映射类
【发布时间】:2013-03-21 21:37:08
【问题描述】:

我有几个相同的实体,除了每个都映射到相应的相同表的类名。每个表的映射类似于以下内容:

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

这种方法有效,但重复。

我创建了这个类,希望摆脱重新定位。为简洁起见,此处进行了简化。

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

我收到以下我不理解的编译器错误:

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>()'
  • 与许多 .Net 编码人员一样,我经常使用泛型,但不经常编写它们。
  • 我使用 EF 有一段时间了,但我对 Code First 还是很陌生
  • 我在 SO 上下进行了很多搜索,但都没有运气。
  • 我做错了什么?我有什么不明白的?

提前致谢, 吉姆

【问题讨论】:

    标签: entity-framework ef-code-first entity-framework-5


    【解决方案1】:

    只需添加泛型参数约束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);
            });
        }
    }
    

    DbModelBuilder.Entity&lt;T&gt; 方法上存在相同的约束,这就是为什么您需要在泛型类中使用相同的约束。

    【讨论】:

      【解决方案2】:

      错误表明您的泛型缺少class 约束。 Read here 关于“类型参数的约束”。

      所以Generic&lt;T&gt; 应该声明为

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

      但我建议使用EntityTypeConfiguration。此类将允许您将实体映射与上下文分离并实现您想要的一种继承。

      例如:

      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");
          }
      }
      

      此类声明所有实体都将具有到名称与类型名称相同的表的映射,并且每个表都有一个名称为 &lt;TableName&gt;Id 的主键列。

      那么实体Foo的映射配置可以声明如下:

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

      然后配置应该注册到 DbContext 中:

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

      【讨论】:

      • 感谢您的出色回答和额外信息。我已经将较早的回复标记为答案。但是,我想让你知道我很欣赏这些额外的信息。我总是喜欢学习新东西。
      【解决方案3】:

      EF 提供了一个允许你这样做的类:

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

      然后,在您的 DbContext 中,覆盖 OnModelCreating 并将映射添加到配置中:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-05
        • 2014-08-31
        • 2012-09-27
        • 1970-01-01
        • 1970-01-01
        • 2011-08-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多