EF6 M:M 没有 Bridge/Junction Class,非常规 FK

EF6 M:M Without Bridge/Junction Class, Unconventional FKs

尝试用 EF6 围绕 M:M。我有一个现有的数据库,并且在模型创建时使用流利的 API 手动处理代码中的模型。

正如我所读并且对我有意义的那样,当数据库模式包含一个没有有效负载(额外字段)的联结 table 时,代表 class 不必是 EF6 的一部分模型。相反,M:M 的每一端都有其另一端的集合,如下所示:

CREATE TABLE dbo.Personnel (
    ID INT NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1, 1),
    CompanyID INT NOT NULL REFERENCES dbo.Company (ID) ON UPDATE CASCADE ON DELETE CASCADE,
    PersonFirstName NVARCHAR(50) NOT NULL
    -- etc etc
);

CREATE TABLE dbo.Roles (
    ID INT NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1, 1),
    CompanyID INT NOT NULL REFERENCES dbo.Company (ID) ON UPDATE CASCADE ON DELETE CASCADE,
    RoleName NVARCHAR(50) NOT NULL
    -- etc etc
);

CREATE TABLE dbo.PersonnelRoles (
    ID INT NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1, 1),
    RoleID INT NOT NULL REFERENCES dbo.Roles (ID) -- blah blah
    PersonnelID INT NOT NULL REFERENCES dbo.Personnel(ID) -- blah blah
);

我设想我的模型是这样的:

public class Person() 
{
    public int ID {get;set;}
    public int CompanyID {get;set;}
    public string FirstName {get;set;}

    public virtual Company Company {get;set;}
    public virtual ICollection<Role> Roles {get;set;}
}

public class Role() 
{
    public int ID {get;set;}
    public int CompanyID {get;set;}
    public string Name {get;set;}

    public virtual Company Company {get;set;}
    public virtual ICollection<Person> Personnel {get;set;}
}

问题 1

数据库联结 table 具有 ID 的代理主键。这是否足以摆脱 EF 模型不应需要桥 class 的观念?这 "ID" 是否算作一个附加字段,需要在代码中对桥 class 建模? (我真的希望避免这种情况,但外部约定意味着我必须按原样使用数据库模式)。

如果我已经做错了,我们可以跳过问题 2,我会用桥再试一次 class。

问题 2

假设我实际上不需要 class 桥并且我显示的两个模型都是正确的,我如何使用流畅的 API 来设置正确的 FK?当我现在尝试 运行 插入代码时,我得到以下信息:

An error occurred while saving entities that do not expose foreign key properties for their relationship...

顶级异常建议的内部异常是:

Invalid object name 'dbo.RolePersons'

我的 DbContext 看起来像这样:

public DbSet<Person> Personnel { get; set; }
public DbSet<Role> Roles { get; set; }

并在 OnModelCreating 中...

        modelBuilder.Entity<Person>().ToTable("Personnel");
        modelBuilder.Entity<Person>().Property(e => e.FirstName).HasColumnName("PersonFirstName");
        modelBuilder.Entity<Person>().Property(e => e.LastName).HasColumnName("PersonLastName");
        modelBuilder.Entity<Person>().Property(e => e.Gender).HasColumnName("PersonGender");

        modelBuilder.Entity<Role>().Property(e => e.Name).HasColumnName("RoleName");
        modelBuilder.Entity<Role>().Property(e => e.Code).HasColumnName("RoleCode");
        modelBuilder.Entity<Role>().Property(e => e.Description).HasColumnName("RoleDescription");

我查看了相关问题和答案并查看了 HasRequiredHasKey,但我不确定如何在此处应用它们:table [=48] =] 要求 roles/persons 在交汇处,并且两个 table 中的任何一个都引用另一个密钥...

我可以在不需要桥的情况下对此建模吗 class,如果可以,我如何指示 EF 这样做?谢谢。

我相信您已正确设置所有内容。您收到的错误是因为 EF 期望连接 table 的名称是 RolePersons,而不是 PersonnelRoles。

要解决此问题,您必须在 OnModelCreating 中指定关系。您可以通过添加:

modelBuilder.Entity<Role>()
    .HasMany(p => p.Personnel)
    .WithMany(r => r.Roles)
    .Map(r=> { 
        r.ToTable("PersonnelRoles");
        r.MapLeftKey("RoleID");
        r.MapRightKey("PersonnelID");
     });