实体框架外键引用没有映射

时间:2018-05-26 15:06:38

标签: c# entity-framework

使用EF6和.NET 4.6.1。我知道这有点重复(我看过this stack overflow post)但是听我说。我的情况有所不同,我试图让它与我的解决方案一起工作,但它没有用。所以不,这实际上并不重复。这完全是另一个问题,我还没有找到真正帮助我解决这个问题的帖子。

我试图映射3个模型之间的关系; EmployeePositionEmployment。我想要EmploymentPosition之间的一对多(就业映射到一个职位)和EmploymentEmployee之间的一对一。

public class Employment
{
    public int EmploymentID { get; set;}
    ...
    public Position Position { get; set; }
    public Employee Employee { get; set; }
}

public class Position
{
    public int PositionID { get; set;}
    ...
    [InverseProperty("Position")]
    public ICollection<Employment> Employments { get; set; }
}

public class Employee
{
    public int EmployeeID { get; set;}
    ...
    [InverseProperty("Employee")]
    public Employment Employment { get; set; }
}

但是,当我尝试使用DbContext自动执行时运行此功能时,它会失败并说它无法找到关系。我尝试了多种数据注释组合,例如设置inversepperties和foreignkey(&#34; ____ ID&#34;),但是还没有能够让它工作。

我也尝试为某些人添加虚拟关键字,但也没有做任何事情。

我不想使用FluentAPI,因为我想让自动映射器尽可能地使用它。它不是一个复杂的问题,不足以保证用FluentAPI手动映射它(至少在我看来它不是。也许我错了)。

我需要哪些数据注释?我查看了this stack overflow postentityframeworktutorial.net上的各种文章,试图将他们的解决方案应用到我的案例中。但是没有什么可以发挥作用。

失败的行在这里:

using (EmploymentContext ctx = new EmploymentContext())
{
    Position pos = new Position()
    {
        PositionID=1,
        Name="General Manager"
    };
    ctx.Positions.Add(pos); // Failing here
    ctx.SaveChanges();
}

,错误信息为:

  

&#39;无法确定类型'Ianmann.Hr.DataAccess.Employment.EmployeeIanmann.Hr.DataAccess.Employment.Employment之间关联的主要结尾。必须使用关系流畅API或数据注释显式配置此关联的主要结尾。&#39;

1 个答案:

答案 0 :(得分:3)

我不知道为什么你坚持使用数据注释。您可以使用Fluent API完成数据注释所能完成的所有工作,但事实恰恰相反。此外,特别是对于关系,数据注释不直观且容易出错。

在具体情况下,问题在于一对一关系(顺便说一句,错误消息应该包含该信息)。这是因为当关系的两端都是可选的(如你的情况)或两者都需要时,EF无法确定关系的主体和依赖关系。因此,解决它的一种方法是通过制作所需的导航属性来标记主体:

public class Employment
{
    public int EmploymentID { get; set; }
    ...
    public Position Position { get; set; }

    [Required] // <--
    public Employee Employee { get; set; }
}

在这种情况下,InverseProperty是多余的(不需要)。

使用流畅的API可以更直观地实现同样的目标:

modelBuilder.Entity<Employment>()
    .HasRequired(e => e.Employee)
    .WithOptional(e => e.Employment);

但请注意,虽然任何一种方法都可以解决相关问题,但最终的设计将是所谓的Shared Primary Key association,其中EmploymentID既是PK又是FK到Employee。如果您需要单独的FK属性/列,则必须使用流畅的API,因为无法通过数据注释完成:

modelBuilder.Entity<Employment>()
    .HasRequired(e => e.Employee)
    .WithOptional(e => e.Employment)
    .Map(m => m.MapKey("EmployeeID"));