3

这里有业务需求,简言之:建模员工-助理(S)与EF代码优先关系

  • 所有员工需要被存储在数据库中
  • 有些员工有助理 ,有的没有
  • 有些员工有一个以上的助理
  • 助理是员工,以及

显然有一点自我参照的情况。但与典型的“员工经理”情况的不同之处在于,这里一名员工可以有0个或多个助理。所以,员工和员工的助理需要的组合存储在一个单独的表中一个一对多的关系员工EmployeeAssistant之间。但是我很困惑如何在Entity Framework 6 Code First中对此进行建模。

我开始用这样的:

public class Employee 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

public class EmployeeAssistant 
{ 
    [ForeignKey("Employee")] 
    public int EmployeeId { get; set; } 
    public virtual Employee Employee { get; set; } 

    [ForeignKey("Assistant")] 
    public int AssistantId { get; set; } 
    public virtual Employee Assistant { get; set; } 
} 

但我Update-Database命令时出现错误:

表 'EmployeeAssistant' 可能会导致循环引进国外KEY约束 'FK_dbo.EmployeeAssistant_dbo.Employee_EmployeeId'或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。

我错过了什么?我应该采取不同的方式吗?

+2

也许这将帮助你:http://stackoverflow.com/ questions/14489676/entity-framework-how-to-solve-foreign-key-constraint-may-cause-cycles-or-multi –

回答

0

基于此链接Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why?

,如果你删除你的代码的EmployeeAssistant看来,它会导致2级联删除路径

我建议这样的结构,因为这样:

编辑

public class Employee 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public List<EmployeeAssistant> Assistants { get; set; } //if an employee has no assistants this List can easily just be empty 
    OR 
    public ICollection<EmployeeAssistant> Assistants { get; set; } // depending on your architecture, choose the one that would suit you better 
} 
public class EmployeeAssistant 
{ 
    [ForeignKey("Employee")] 
    public int EmployeeId { get; set; } //this is the employee who 'has' this assistant 
    public virtual Employee Employee { get; set; } 

    public int Id { get; set; } //this is the assistant's own information - identical to employee's basic info 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

一会儿脑难以置信的后

后,我甚至想到了一个可能性,你只需要1级,员工,但它包括表示该员工是否为助理的bool IsAssistant,以及具有此助理的员工的员工ID AssistantEmployeeId。 例如:

public class Employee 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public bool IsAssistant { get; set; } 
    public int EmployeeAssistantID { get; set; } 
} 

我知道这第二种方法是非常混乱,可能不适合您的需要,但我个人总是先创建数据库表,然后做“从数据库生成模式”,所以我在经验不足代码优先的方法。

+0

嗯,但你怎么知道哪个助手跟哪个员工在一起?如果EmployeeAssistant实体只有'Employee'引用,那么这将在数据库'EmployeeAssistant'中创建一个具有'Id'和'EmployeeId'字段的表。因此,它缺少将员工绑定到助理的数据。对? – Jiveman

+0

我在编辑后重新阅读您的答案。我欣赏这个令人难以置信的大脑!然而,第一种方法意味着我必须复制EmployeeAssistant类中的所有Employee属性,并且这没有意义,因为EmployeeAssistant本身就是Employee。第二种方法不起作用,因为它只处理一个助理案件,而不是多个助理。 – Jiveman

+0

然后在第二种方法中添加一个EmployeeAssistantIDs列表可以做到这一点吗?例如'公开列表 AssistantIDs {get;组; }' –

1

因为每个员工可能有一个或多个助理(每个助理将有一个或多个员工)并且全部都是员工,最简单的解决方案是一个类,其中有两个助理和员工的集合,关系将由框架:

public class Employee 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public ICollection<Employee> Assistants { get; set; } 
    public ICollection<Employee> Employees { get; set; } 
} 

当您使用包管理器控制台添加迁移它会自动创建两个表,一个员工,另一个是多对多的关系。

那么您所要做的就是使用包含扩展方法找到相关助理和/或员工。

db.Employees.Where(X => x.Id == ID).INCLUDE(X => x.Assistants).FirstOrDefault()

和/或

db.Employees.Where(X => x.Id == ID).INCLUDE(X => x.Employees).FirstOrDefault()

+0

嗯,没想到这会起作用,但它呢!我唯一的问题是,生成的多对多表的名称为EmployeeEmployee,其中的字段为Employee_Id和Employee_Id1。有没有办法通过数据注释(最好)或使用Fluent映射来控制这些元素的名称? – Jiveman

+0

您不必更改这些字段,因为您不会使用它,框架将为您执行肮脏的工作:) btw,在从employees表中删除实体之前,您必须清除其与其他实体的关系。 – Ziyad

+0

是的,我知道我不需要,但我需要数据库本身才有意义,因为它将用于报告和其他潜在的直接查询。我不能仅仅将它用作“黑匣子”数据持久性。我发现如何用流利的映射来做到这一点,只是不确定如何使用数据注释来做到这一点,如果它甚至是可能的。当我有机会时,会提供更多细节的答案。 – Jiveman