当两个表之间存在链接(连接)表时,我对两个表之间的一对多关系有疑问。
示例表:
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();
}
一切都按预期工作,但我真的只有一个父母和很多孩子。
如何进行包含写入链接表的映射(更改后的ChildTable类没有使用ParentTable的ICollection)?
答案 0 :(得分:7)
无法定义此类映射。连接表仅适用于多对多关系。您必须记住,您的数据库架构(您无法更改,正如您在问题的评论中所述)已经定义了多对多关系。例如,这两个条目......
ParentTable_ID: 1 2
ChildTable_ID: 1 1
...是ParentChildren
表中的有效条目,它们不违反PK约束,并且他们说孩子1有两个父母1和2。
如果您的业务逻辑仅允许子级只有一个父级,则数据库架构的建模错误。你不能用EF修复这个漏洞。
可能的解决方法可能是在代码中的业务逻辑中确保ParentTables
实体的ChildTable
集合永远不会有多个元素,可能是通过引入未映射的帮助程序属性:< / p>
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; }
[NotMapped] // or use .Ignore(c => c.ParentTable) in Fluent API
public ParentTable ParentTable
{
get
{
return ParentTables.SingleOrDefault();
// let is crash if there is more than one element in the list
}
set
{
var oldParent = ParentTables.SingleOrDefault();
if (oldParent != value)
{
ParentTables.Clear();
if (value != null)
ParentTables.Add(value);
}
}
}
}
如果您只使用ParentTable
属性,那只会有一点帮助。您必须避免使用该集合并添加多个父级。你不能使它private
,因为它必须被映射。在这段关系的另一边也不安全。您可以编写:parent1.ChildTables.Add(child1); parent2.ChildTables.Add(child1);
,这将导致数据库中child1
的两个父项。您可以通过编写帮助方法来捕获这一点,该方法用于在ParentTable
实体上添加子项,以检查添加的子项是否还没有this
父项以外的父项。