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");
我查看了相关问题和答案并查看了 HasRequired
和 HasKey
,但我不确定如何在此处应用它们: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");
});
尝试用 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");
我查看了相关问题和答案并查看了 HasRequired
和 HasKey
,但我不确定如何在此处应用它们: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");
});