EF6 M:M无桥/结类,非常规FK

时间:2016-07-04 03:52:52

标签: c# entity-framework entity-framework-6 ef-fluent-api

试着用EF6把头包裹在M:M附近。我有一个现有的数据库,我在代码中手动处理模型,使用模型创建的流畅API。

正如我已阅读并且对我而言,当db模式包含没有有效负载的联结表(额外字段)时,代表类不必是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

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

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

问题2

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

  

保存未公开其关系的外键属性的实体时发生错误...

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

  

无效的对象名称'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,但我不确定如何在这里应用它们:表都不需要角色/人员在交界处,两个表中的任何一个都引用另一个表的键...

我可以在不需要桥接类的情况下对其进行建模,如果是这样,我该如何指示EF这样做?感谢。

1 个答案:

答案 0 :(得分:1)

我相信你已经正确设置了一切。您得到的错误是因为EF期望连接表的名称是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");
     });