C# EF6 实体映射

C# EF6 entity mapping

我目前正在开发一个项目(WCF 服务),该项目应将 EF6 与 MySql 数据库结合使用。该部分本身已经可以正常工作,但是我在映射方面遇到了很大的问题。

我有如下 3 个实体:

Employee - ManyToMany - Project - OneToMany - ProjectStep

我的数据库模型是这样设置的:

员工table:

CREATE TABLE `employee` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` varchar(255) DEFAULT NULL,
  `JobDescription` varchar(255) DEFAULT NULL,
  `Department` varchar(255) DEFAULT NULL,
  `DirectDialing` varchar(255) DEFAULT NULL,
  `Status` bit(1) DEFAULT NULL,
  PRIMARY KEY (`ID`)
)

项目 table:

CREATE TABLE `project` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Titel` varchar(255) DEFAULT NULL,
  `StartDate` datetime DEFAULT NULL,
  `EndDate` datetime DEFAULT NULL,
  `Description` varchar(255) DEFAULT NULL,
  `ProjectLeader` int(11) DEFAULT NULL,
  `Status` int(11) DEFAULT NULL,
  PRIMARY KEY (`ID`),
  CONSTRAINT `project_fk` FOREIGN KEY (`ProjectLeader`) REFERENCES `employee` (`ID`)
)

ProjectStep table:

CREATE TABLE `project_step` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Description` text,
  `StartDate` datetime DEFAULT NULL,
  `EndDate` datetime DEFAULT NULL,
  `Project` int(11) DEFAULT NULL,
  PRIMARY KEY (`ID`),
  CONSTRAINT `project_step_fk` FOREIGN KEY (`Project`) REFERENCES `project` (`ID`)
)

映射table员工 - 项目

CREATE TABLE `employee_project` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `EmployeeId` int(11) DEFAULT NULL,
  `ProjectId` int(11) DEFAULT NULL,
  PRIMARY KEY (`ID`),
  CONSTRAINT `projectId_fk` FOREIGN KEY (`ProjectId`) REFERENCES `project` (`ID`)
  CONSTRAINT `employeeId_fk` FOREIGN KEY (`EmployeeId`) REFERENCES `employee` (`ID`)
)

然后我创建了如下实体:

[DataContract(Namespace = "Shared")]
public class Employee
{
    public Employee()
    {
        this.Projects = new List<Project>();
    }

    [DataMember]
    [Key]
    public int ID { get; set; }

    [DataMember]
    public String Name { get; set; }

    [DataMember]
    public String Berufsbezeichnung { get; set; }

    [DataMember]
    public String Abteilung { get; set; }

    [DataMember]
    public String Durchwahl { get; set; }

    [DataMember]
    public bool Status { get; set; }

    [DataMember]
    public virtual ICollection<Project> Projects { get; set; }
}

[DataContract(Namespace = "Shared")]
public class Project
{

    public Project()
    {
        this.EmployeesWorkingOnProject = new List<Employee>();
        this.ProjectSteps = new List<ProjectStep>();
    }

    [DataMember]
    [Key]
    public int ID { get; set; }

    [DataMember]
    public String Titel { get; set; }

    [DataMember]
    public DateTime StartDatum { get; set; }

    [DataMember]
    public DateTime EndDatum { get; set; }

    [DataMember]
    public String Beschreibung { get; set; }

    [DataMember]
    [Column("Projektleiter")]
    public Employee Projektleiter { get; set; }

    [DataMember]
    public bool Status { get; set; }

    [DataMember]
    public virtual ICollection<Employee> EmployeesWorkingOnProject { get; set; }

    [DataMember]
    [ForeignKey("Project")]
    public virtual ICollection<ProjectStep> ProjectSteps { get; set; }
}

[DataContract(Namespace = "Shared")]
public class ProjectStep
{
    [DataMember]
    public int ID { get; set; }

    [DataMember]
    public String Beschreibung { get; set; }

    [DataMember]
    public DateTime StartDatum { get; set; }

    [DataMember]
    public DateTime EndDatum { get; set; }

    [DataMember]
    public Project Project { get; set; }
}

并使用 Fluent API 创建 ManyToMany 关系以及 OneToMany:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    modelBuilder.Entity<Employee>().HasMany(e => e.Projects).WithMany(t => t.EmployeesWorkingOnProject).Map(m =>
    {
        m.MapLeftKey("MitarbeiterID");
        m.MapRightKey("ProjektID");
        m.ToTable("mitarbeiter_projekte");
    });

    modelBuilder.Entity<ProjectStep>().HasRequired<Project>(p => p.Project).WithMany(p => p.ProjectSteps);
}

我真的很茫然,因为当我试图插入一个新的Project时,我得到了错误:

The ForeignKeyAttribute on property 'ProjectSteps' on type 'Shared.Project' is not valid. The foreign key name 'Project' was not found on the dependent type 'Shared.ProjectStep'. The Name value should be a comma separated list of foreign key property names.

我认为我的映射存在一些问题,这是导致此错误的原因。我完全不知道我的映射在哪里是错误的,甚至我什至使用了正确的方法。

所以我的问题是,是否应该将 DataAnnotationsFluent API 混合使用,有人可以帮助我正确映射吗?

请注意,这是我的第一个 C#/EF6 项目,我对所有事情都不太熟悉,所以欢迎提供一些解释。

为了能够向数据库添加新的 "Project",您需要从 "ProjectSteps" 属性 中删除 "Project" [=26] 中的外键注释=]. "Foreign Key" 注解只能应用于非集合类型的属性。

[DataContract(Namespace = "Shared")]
public class Project
{

    public Project()
    {
        this.EmployeesWorkingOnProject = new List<Employee>();
        this.ProjectSteps = new List<ProjectStep>();
    }

    [DataMember]
    [Key]
    public int ID { get; set; }

    [DataMember]
    public String Titel { get; set; }

    [DataMember]
    public DateTime StartDatum { get; set; }

    [DataMember]
    public DateTime EndDatum { get; set; }

    [DataMember]
    public String Beschreibung { get; set; }

    [DataMember]
    [Column("Projektleiter")]
    public Employee Projektleiter { get; set; }

    [DataMember]
    public bool Status { get; set; }

    [DataMember]
    public virtual ICollection<Employee> EmployeesWorkingOnProject { get; set; }

    [DataMember]
    public virtual ICollection<ProjectStep> ProjectSteps { get; set; }
}

另外回答你的问题:

So my question is, should one even mix the DataAnnotations with Fluent API, and could someone help me getting this mapping right?

混用不是一个好习惯。 Imho Fluent API 总是更好,因为它提供了更多的映射选项。

有关 EF 映射的详细信息,请查看 THIS

数据注释和流畅的配置可以混合使用。但特别是对于关系,我发现流畅的配置更加直观。 ForeignKey 属性的问题在于它可以应用于 FK 属性,在这种情况下它用于指定导航 属性 名称。或者它可以应用于导航 属性,在这种情况下它应该包含 FK 属性 名称(或复合 FK 的逗号分隔列表 属性 名称)。

需要知道的重要一点是它不能用于指定外键名称。列名由 Column 属性控制,因此只有当您具有明确的 FK 属性(您没有)时才能使用它。

Fluent API 没有这样的限制。当你有明确的 FK 属性 时,你可以使用 HasForeignKey,或者当你没有时使用 MapMapKey

在您的情况下,为了将不寻常的 "Project" 指定为 FK 列名称,您可以使用以下流畅的配置(并且不要忘记从 ProjectSteps):

modelBuilder.Entity<ProjectStep>()
    .HasRequired(p => p.Project)
    .WithMany(s => s.ProjectSteps)
    .Map(m => m.MapKey("Project"));