实体框架代码优先与链接表的一对多关系映射
当两个表之间存在链接(联接)表时,我有一个关于两个表之间的一对多关系的问题。
示例表:
ChildTable:
ID int NOT NULL PK
Relation int NOT NULL
ParentTable:
ID int NOT NULL PK
Name nvarchar(50) NOT NULL
ParentChildren:
ParentTable_ID int NOT NULL PFK
ChildTable_ID int NOT NULL PFK
实体:
public class ChildTable
{
public ChildTable()
{
this.ParentTables = new List<ParentTable>();
}
public int ID { get; set; }
public int Relation { get; set; }
public virtual ICollection<ParentTable> ParentTables { get; set; }
}
public class ParentTable
{
public ParentTable()
{
this.ChildTables = new List<ChildTable>();
}
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<ChildTable> ChildTables { get; set; }
}
映射:
public class ChildTableMap : EntityTypeConfiguration<ChildTable>
{
public ChildTableMap()
{
// Primary Key
this.HasKey(t => t.ID);
// Properties
// Table & Column Mappings
this.ToTable("ChildTable");
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.Relation).HasColumnName("Relation");
}
}
public class ParentTableMap : EntityTypeConfiguration<ParentTable>
{
public ParentTableMap()
{
// Primary Key
this.HasKey(t => t.ID);
// Properties
this.Property(t => t.Name)
.IsRequired()
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("ParentTable");
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.Name).HasColumnName("Name");
// Relationships
this.HasMany(t => t.ChildTables)
.WithMany(t => t.ParentTables)
.Map(m =>
{
m.ToTable("ParentChildren");
m.MapLeftKey("ParentTable_ID");
m.MapRightKey("ChildTable_ID");
});
}
}
上下文:
public class TestContext : DbContext
{
static TestContext()
{
Database.SetInitializer<TestContext>(null);
}
public DbSet<ChildTable> ChildTables { get; set; }
public DbSet<ParentTable> ParentTables { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
modelBuilder.Configurations.Add(new ChildTableMap());
modelBuilder.Configurations.Add(new ParentTableMap());
}
}
添加子级和父级的代码:
using (var context = new TestContext())
{
var parent = new ParentTable { Name = "Mother Goose" };
var child = new ChildTable { Relation = 1 };
context.ParentTables.Add(parent);
context.ChildTables.Add(child);
parent.ChildTables.Add(child);
context.SaveChanges();
}
一切都按预期工作,但我实际上只有 1 个父级和许多子级。
如何进行包括写入链接表的映射(使用更改后的 ChildTable 类,该类没有 ParentTable 的 ICollection)?
I have a question about One-To-Many relationship between two tables when there is the link (join) table between.
Example tables:
ChildTable:
ID int NOT NULL PK
Relation int NOT NULL
ParentTable:
ID int NOT NULL PK
Name nvarchar(50) NOT NULL
ParentChildren:
ParentTable_ID int NOT NULL PFK
ChildTable_ID int NOT NULL PFK
Entities:
public class ChildTable
{
public ChildTable()
{
this.ParentTables = new List<ParentTable>();
}
public int ID { get; set; }
public int Relation { get; set; }
public virtual ICollection<ParentTable> ParentTables { get; set; }
}
public class ParentTable
{
public ParentTable()
{
this.ChildTables = new List<ChildTable>();
}
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<ChildTable> ChildTables { get; set; }
}
Mapping:
public class ChildTableMap : EntityTypeConfiguration<ChildTable>
{
public ChildTableMap()
{
// Primary Key
this.HasKey(t => t.ID);
// Properties
// Table & Column Mappings
this.ToTable("ChildTable");
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.Relation).HasColumnName("Relation");
}
}
public class ParentTableMap : EntityTypeConfiguration<ParentTable>
{
public ParentTableMap()
{
// Primary Key
this.HasKey(t => t.ID);
// Properties
this.Property(t => t.Name)
.IsRequired()
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("ParentTable");
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.Name).HasColumnName("Name");
// Relationships
this.HasMany(t => t.ChildTables)
.WithMany(t => t.ParentTables)
.Map(m =>
{
m.ToTable("ParentChildren");
m.MapLeftKey("ParentTable_ID");
m.MapRightKey("ChildTable_ID");
});
}
}
Context:
public class TestContext : DbContext
{
static TestContext()
{
Database.SetInitializer<TestContext>(null);
}
public DbSet<ChildTable> ChildTables { get; set; }
public DbSet<ParentTable> ParentTables { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
modelBuilder.Configurations.Add(new ChildTableMap());
modelBuilder.Configurations.Add(new ParentTableMap());
}
}
Code to add the child and parent:
using (var context = new TestContext())
{
var parent = new ParentTable { Name = "Mother Goose" };
var child = new ChildTable { Relation = 1 };
context.ParentTables.Add(parent);
context.ChildTables.Add(child);
parent.ChildTables.Add(child);
context.SaveChanges();
}
And all works as expected, but I really have only 1 parent and many children.
How to do the mapping that includes writing to the link table (with changed ChildTable class that does not have the ICollection of ParentTable)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不可能定义这样的映射。连接表仅适用于多对多关系。您必须记住,您的数据库架构(正如您在问题评论中所说的那样,无法更改)已经定义了多对多关系。例如,这两个条目...
...是
ParentChildren
表中的有效条目,它们不违反 PK 约束,并且它们表示子项 1 有两个父项 1 和 2。如果您的业务逻辑只允许子项只能有一个父项,数据库模式建模错误。您无法使用 EF 修复此缺陷。
一种可能的解决方法可能是确保在代码中的业务逻辑中,
ChildTable
实体的ParentTables
集合永远不会有多个元素,也许可以通过引入未映射的帮助程序属性:如果您只使用
ParentTable
属性,那么这只是一点帮助。您必须避免使用该集合并添加多个父级。您不能将其设为私有
,因为它必须被映射。关系的另一方也不安全。您可以编写:parent1.ChildTables.Add(child1); Parent2.ChildTables.Add(child1); 这将导致数据库中child1
的两个父级。您可以通过编写用于在ParentTable
实体上添加子项的辅助方法来捕获此问题,该方法检查添加的子项是否尚未具有除this
父级之外的父级。It's not possible to define such a mapping. Join tables are only for many-to-many relationships. You have to keep in mind that your database schema (which you cannot change, as you said in the comments to your question) already defines a many-to-many relationship. For example these two entries...
...are valid entries in the
ParentChildren
table, they don't violate the PK constraint and they say that child 1 has the two parents 1 and 2.If your business logic only allows that a child can have only one single parent, the database schema is modeled wrong. You cannot fix this flaw with EF.
A possible workaround might be to ensure in your business logic in your code that the
ParentTables
collection of yourChildTable
entity never has more than one element, perhaps by introducing a not mapped helper property:It's only a little help if you only use the
ParentTable
property. You have to avoid to use the collection and add more than one parent. You cannot make itprivate
because it must be mapped. It's also not safe on the other side of the relationship. You could write:parent1.ChildTables.Add(child1); parent2.ChildTables.Add(child1);
which would lead to two parents forchild1
in the database. You could catch this by writing helper methods for adding a child on theParentTable
entity which check if the added child doesn't already have a parent other thanthis
parent.