【问题标题】:C# EF6 entity mappingC# EF6 实体映射
【发布时间】:2018-03-31 18:05:09
【问题描述】:

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

我有 3 个实体,如下所示:

Employee - ManyToMany - Project - OneToMany - ProjectStep

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

员工表:

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`)
)

项目表:

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 表:

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`)
)

映射表员工 - 项目

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 时,我得到了错误:

类型上属性“ProjectSteps”的 ForeignKeyAttribute “Shared.Project”无效。外键名称“项目”不是 在依赖类型“Shared.ProjectStep”上找到。名称值 应该是逗号分隔的外键属性名称列表。

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

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

请注意,这是我的第一个 C#/EF6 项目,我对所有内容都不是很常见,因此欢迎提供一些解释。

【问题讨论】:

  • 我认为您需要使用Id 字段作为外键,例如ProjectId。收藏不能成为钥匙,不是吗?我只比你稍微熟悉一点,但似乎你不应该先用 Fluent 做一些,用 DataAnnotations 做一些,而先通过数据做一些。您可以通过这三种方式中的任何一种来设置约束,那么为什么不将它们全部合二为一呢?
  • @Tim 出于某种原因data first 在我的 VS 中不起作用。 DataAnnotations 还需要一个实体来映射 ManyToMany 对吗?

标签: c# .net entity-framework ef-fluent-api


【解决方案1】:

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

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

Fluent API 没有这样的限制。当你有明确的 FK 属性时,你要么使用 HasForeignKey,要么在没有明确的 FK 属性时使用 MapMapKey

在您的情况下,为了将您不寻常的“项目”指定为 FK 列名称,您可以使用以下流畅的配置(不要忘记从 ProjectSteps 中删除无效的 ForeignKey 属性):

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

【讨论】:

  • fixed size Arrays 有多个问题。你知道是什么原因造成的吗?
  • 固定大小的数组?我不认为 EF 支持这样的事情。但您可以发布另一个问题,准确显示有问题的案例。
  • 我的意思是我的列表中出现的错误:InvalidOperationException: An item cannot be added to a fixed size Array of type 'Shared.ProjectStep[]'.
  • 我明白了。没有看到用例就无法判断,但很可能与 WCF 序列化有关。 ICollection&lt;ProjectStep&gt; 允许分配 ProjectStep[]。如果不是您自己的代码,我猜应该是 WCF。刚刚找到这个stackoverflow.com/questions/10244910/…。看起来解决方法是使用 List&lt;T&gt; 而不是 ICollection&lt;T&gt; 导航属性类型。
  • 已经试过了,但是没有用。将针对该问题提出新问题
【解决方案2】:

为了能够将新的“Project”添加到 db,您需要从“Project”类的“ProjectSteps”属性中删除外键注释。 “外键”注解只能应用于非集合类型的属性。

[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; }
}

另外回答你的问题:

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

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

有关 EF 映射的更多信息,请查看THIS

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-25
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 2017-09-30
    • 1970-01-01
    相关资源
    最近更新 更多