首页 > 解决方案 > EF Core 中的一对零或一对关系

问题描述

让我简化一下:

给定两个模型

Department模型

    public Guid Id { get; set; }
    public string DepartmentID { get; set; }
    public string DepartmentName { get; set; }
    public Guid? DepartmentManager { get; set; } 

Employee模型

    public Guid ID { get; set; }
    public string EmployeeID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }

我希望能够分配一名 - 并且只有一名 - 员工作为部门的部门经理。

示例:部门是财务。部门经理是 Joe, Blow。

部门模型中的 DepartmentManager 应包含来自员工模型的 Joe Blow 的 EmployeeID

我认为一旦我在模型中得到正确的关系,我将能够完成 cshtml 页面以正确处理 CRUD。

谢谢,约翰

标签: c#entity-framework-core

解决方案


假设这些是您的模型类:

public class Department
{
    public Guid Id { get; set; }
    public string DepartmentID { get; set; }
    public string DepartmentName { get; set; }
    public Guid? DepartmentManager { get; set; } 
}

public class Employee
{
    public Guid ID { get; set; }
    public string EmployeeID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
}

您有几个选项可以显式配置实体(数据模型)之间的关系。

一、数据属性

如果您对 Fluent API 不满意,您可以使用数据属性装饰您的模型,EF 会在内存中构建模型时发现并使用这些属性。所以,对于你的情况,这样的事情是有效的:

[Table(nameof(Department))]
public class Department
{
    [Key]
    public Guid Id { get; set; }
    public string DepartmentID { get; set; }
    public string DepartmentName { get; set; }

    [ForeignKey(nameof(DepartmentManager))]
    public Guid? DepartmentManagerID { get; set; } 

    public virtual Employee DepartmentManager { get; set; }
}

[Table(nameof(Employee))]
public class Employee
{
    public Employee()
    {
        Departments = new HashSet<Department>();
    }

    [Key]
    public Guid ID { get; set; }
    public string EmployeeID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }

    public virtual ICollection<Department> Departments { get; set; }
}

TableAttribute是可选的 - 我用它来明确声明表使用单数命名约定(因此表称为“部门”,而不是“部门”)。KeyAttribute也应该是可选的,因为 EF 的约定之一是假设“ID”字段是主键,但再次[Key]使其明确(在这里感知主题?)。

我还建议使用DepartmentManagerID作为外键属性,而不是DepartmentManager,以保持一致。这还允许您添加一个导航属性 ,DepartmentManager该属性可用于在查询部门时包含员工记录。

Employeecan (should?) 还有一个导航属性 ,Departments代表 Employee 和 Department 之间“一对多”关系的“多”端——一个 Department 只能有一个 Employee(经理),但是一个 Employee 可以管理许多部门。将此virtual属性设为允许 EF 延迟加载该属性,因此您可以查询员工记录,而无需始终获取关联的部门。

2.流畅的API

除了数据属性之外,还可以使用 fluent API,也可以使用 fluent API(您的选择)。我仍然会添加相关的导航属性,所以你的模型看起来像这样:

public class Department
{
    public Guid Id { get; set; }
    public string DepartmentID { get; set; }
    public string DepartmentName { get; set; }

    public Guid? DepartmentManagerID { get; set; } 

    public virtual Employee DepartmentManager { get; set; }
}

public class Employee
{
    public Employee()
    {
        Departments = new HashSet<Department>();
    }

    public Guid ID { get; set; }
    public string EmployeeID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }

    public virtual ICollection<Department> Departments { get; set; }
}

然后,在您的 DbContext 类中(为了保持这个简单(ish)),您将配置您的模型及其关系:

public partial class JohnsDbContext : DbContext
{
    public JohnsDbContext(DbContextOptions<JohnsDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // To set the table name, uncomment:
        //modelBuilder.Entity<Department>()
        //    .ToTable(nameof(Department));

        modelBuilder.Entity<Department>()
            .HasKey(m => m.ID);

        modelBuilder.Entity<Department>()
            .HasOne(m => m.DepartmentManager)           // Department.DepartmentManager
            .WithMany(m => m.Departments)               // Employee.Departments
            .HasForeignKey(m => m.DepartmentManagerID); // Department.DepartmentManagerID


        modelBuilder.Entity<Employee>()
            .HasKey(m => m.ID);
    }
}

这几乎是使用 fluent API 建立关系的最低要求。如果您需要,还有更多可用的设置,Intellisense 将帮助您发现它们。


推荐阅读