摘要 Class 具有 1 对 1 关系 Entity Framework

Abstract Class with 1 to 1 relationship Entity Framework

使用 entity framework 我一直在尝试建立这种关系。基本上我有 1 个对象,其中有一个 ResultResult 对象是抽象的,因为它必须是继承自 Result 的 3 个 class 之一,即 ApprovedRejectedModified:

我正在尝试使用 Entity Framework 创建 table 结构。最初我打算使用 TPCT(Table 每个混凝土类型)结构,所以不会有 Result table,但我想将 link 保留在 Action table 如果我想引用 Result,那么现在我只尝试 TPT 结构。我发现 TPCT 更简洁,但最终如果 TPT 是实现我想要的目标的唯一方法,我就接受它。

我已经为我的模型结构尝试了以下变体:

public class Action 
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id {get; set;}

    public int Result_Id {get; set;}

    [ForeignKey("Result_Id")]
    public virtual Result Result {get; set;}

    public string Description {get; set;}
}

public abstract class Result
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id {get; set;}

    [Required]
    public int Action_Id {get; set;}

    [ForeignKey("Action_Id")]
    public virtual Action Action {get; set;}

    public string Comment {get; set;}


    public class Approved : Result
    {
        public string Thing {get; set;}
    }

    public class Rejected : Result
    {
        public string Stuff {get; set;}
    }

    public class Modified : Result
    {
        public string Whatever {get; set;}
    }
}

然后我在上下文文件中尝试了以下两种策略来实现 TPT:

modelBuilder.Entity<Approved>().ToTable("Approved");
modelBuilder.Entity<Rejected>().ToTable("Rejected");
modelBuilder.Entity<Modified>().ToTable("Modified");

或者对于 TCPT:

modelBuilder.Entity<Approved>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("Approved");
});

modelBuilder.Entity<Rejected>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("Rejected");
});

modelBuilder.Entity<Modified>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("Modified");
});

每次我尝试添加新的迁移时,无论我尝试什么,我都会遇到这个错误: Unable to determine the principal end of an association between the types 'Result' and 'Action'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

有一次我能够让它工作是因为我从 Action class:

中删除了这个引用
public int Result_Id {get; set;}

[ForeignKey("Result_Id")]
public virtual Result Result {get; set;}

但我真的很想保留那个引用,这样当我进入我的数据库获取那个 Action 对象时,我可以立即判断是否有一个 Result 与之关联,无需检查所有 3 个结果 table 以查看是否存在对 Action 的引用(这就是为什么我认为我需要 TPT...)

如能提供帮助,我们将不胜感激!

通过大量的研究和反复试验,我发现了我需要什么来获得我想要的结果。它是 TPCT DB 结构,Action 对象能够保留对 Result 的引用。这是模型 类:

public class Action 
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id {get; set;}

    public virtual Result Result {get; set;} //just virtual here, as Action is the dependent and Result is the principal-- i.e. this Result isn't required

    public string Description {get; set;}
}

public abstract class Result
{
    //got rid of the Result_Id, since it's 1:1 the Action_Id can be the Key

    [Required, Key] //added "Key"
    public int Action_Id {get; set;}

    [ForeignKey("Action_Id")]
    public Action Action {get; set;} //removed this virtual, as Action is Required for Result, that makes Result the principal

    public string Comment {get; set;}


    public class Approved : Result
    {
        public string Thing {get; set;}
    }

    public class Rejected : Result
    {
        public string Stuff {get; set;}
    }

    public class Modified : Result
    {
        public string Whatever {get; set;}
    }
}

这里是来自上下文的流畅 API 代码:

//this gave me TPCT like I wanted
modelBuilder.Entity<Approved>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("Approved");
});

modelBuilder.Entity<Rejected>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("Rejected");
});

modelBuilder.Entity<Modified>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("Modified");
});

//this defined the principal-dependent relationship I was missing
modelBuilder.Entity<Action>()
    .HasOptional(a => a.Result)
    .WithRequired(a => a.Action)
    .Map(x => x.MapKey("Action_Id"));

然后成功了!希望这个例子可以帮助其他人。