【问题标题】:EF: Map base class property with fluent APIEF:使用流式 API 映射基类属性
【发布时间】:2017-01-23 12:40:05
【问题描述】:

我首先遇到了继承代码的问题。 我有如下所示的基类:

public abstract class BaseEntity
{
    public DateTime? DateCreated { get; set; }
    public string UserCreatedId { get; set; }
    public DateTime? DateModified { get; set; }
    public string UserModifiedId { get; set; }
    public virtual UserState UserCreated { get; set; }
    public virtual UserState UserModified { get; set; }
}

我继承了它,这给了我一个名为 UserCreated_userStateId 和 UserModified_UserStateId 的附加列。所以我尝试了这样的流利的 API:

modelBuilder.Entity<BaseEntity>().HasOptional(x => x.UserCreated).WithMany().HasForeignKey(x => x.UserCreatedId);
modelBuilder.Entity<BaseEntity>().HasOptional(X => X.UserModified).WithMany().HasForeignKey(x => x.UserModifiedId);

但这给了我错误:“在模型生成期间检测到一个或多个验证错误:

BaseEntity: : EntityType 'BaseEntity' 没有定义键。定义此 EntityType 的键。 BaseEntities: EntityType: EntitySet 'BaseEntities' 基于没有定义键的类型 'BaseEntity'。”如何避免定义键而只更改属性映射?我在派生类中有键。

【问题讨论】:

  • 那么您想为每个派生类定义单独的键并使用“每个具体类的表”策略吗?然后你应该在派生类实体上配置基类属性。
  • 如果我理解正确,你使用的不是EF继承,而是简单的C#类继承?
  • 是的,但是我必须有很多派生类来一一配置。这会产生很多复制粘贴代码,我不想要它。它有更好的解决方案吗?是的,我有 C# 类继承,我尝试获取干净的模型并在 fluent API 中获取所有内容。
  • 通常这不需要任何配置。如果 EF 创建其他列,则必须存在类型不匹配 - UserState 类的 PK 属性的 type 是什么?
  • PK 的类型是字符串,但我需要告诉 EF 哪个字符串属性需要是哪个 userState 的 FK,你可以看到我有两个。通常,当我将 FK 命名为 UserStateId 时,EF 会从类名中获取它。

标签: c# entity-framework


【解决方案1】:

您可以将基类配置包装在一个通用方法中,并为每个具体实体类型调用它。

static void ConfigureBaseEntity<TDerived>(EntityTypeConfiguration<TDerived> entityTypeConfiguration) where TDerived : BaseEntity
{
    // your base class configuration
    entityTypeConfiguration.HasOptional(x => x.UserCreated).WithMany().HasForeignKey(x => x.UserCreatedId);
    entityTypeConfiguration.HasOptional(X => X.UserModified).WithMany().HasForeignKey(x => x.UserModifiedId);
}

调用每个具体的实体类型

public class DerivedEntity : BaseEntity
{
    public int Id { get; set; }
}

//...
ConfigureBaseEntity(modelBuilder.Entity<DerivedEntity>());

编辑

也许Types 配置足以满足您的目的。

modelBuilder.Types<BaseEntity>().Configure(entityTypeConfiguration => /* configure using entityTypeConfiguration  */);

否则,如评论所述,您可能需要反思。例如,假设您的所有派生类都与BaseEntity 类在同一个程序集中,而上面的ConfigureBaseEntity 方法在BaseEntityConfiguration 类中。

var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
var configurationMethod = typeof(BaseEntityConfiguration).GetMethod("ConfigureBaseEntity");
foreach (Type t in typeof(BaseEntity).Assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(BaseEntity))))
{
    var configurator = entityMethod.MakeGenericMethod(t).Invoke(modelBuilder, new object[0]);
    configurationMethod.MakeGenericMethod(t).Invoke(null, new object[1] { configurator });
}

但是,如果是我的代码,我更愿意为每个实体类编写一行代码,而不是进行动态发现。

【讨论】:

  • 如果我有很多 DerivedEntity,这个答案会产生很多复制粘贴代码,也许是更干净的方法吗?
  • @CrazyBaran 随意使用反射或 MEF 之类的东西来收集派生类集合并创建我的代码的基于反射的版本,如果每个具体类的单行对您的情况来说非常重要.
  • 好的,第一种方法可行,我想我现在会坚持下去。 +1
猜你喜欢
  • 1970-01-01
  • 2013-02-14
  • 1970-01-01
  • 2015-09-05
  • 2021-02-27
  • 1970-01-01
  • 2018-08-12
  • 2015-10-27
  • 1970-01-01
相关资源
最近更新 更多