(注意:我不同意上述链接,声称这是this的副本)
我正在使用Visual Studio 2010 SP1的实体框架6代码优先(但与Visual Studio 2013的行为相同),针对SQL Server 2012(在Windows 2008 R2上)。
案例1:在多对多关系中有两个实体EntityA和EntityB。连接表使用类JoinAB显式建模。
以下代码有效:
public class EntityA
{
[Key]
public Int64 PK { get; set; }
public string Description { get; set; }
public List<JoinAB> TheBEntities { get; set; }
public EntityA()
{
TheBEntities = new List<JoinAB>();
}
}
public class EntityB
{
[Key]
public Int64 PK { get; set; }
public string SomeData { get; set; }
public List<JoinAB> TheAEntities { get; set; }
public EntityB()
{
TheAEntities = new List<JoinAB>();
}
}
public class JoinAB
{
public Int64 JKey { get; set; }
public Int64 KKey { get; set; }
public EntityA EntityA { get; set; }
public EntityB EntityB { get; set; }
}
public class EntityAConfiguration : EntityTypeConfiguration<EntityA>
{
public EntityAConfiguration()
{
HasMany(x => x.TheBEntities).WithRequired(y => y.EntityA).HasForeignKey(y => y.JKey).WillCascadeOnDelete(true);
}
}
public class EntityBConfiguration : EntityTypeConfiguration<EntityB>
{
public EntityBConfiguration()
{
HasMany(x => x.TheAEntities).WithRequired(y => y.EntityB).HasForeignKey(y => y.KKey).WillCascadeOnDelete(false);
}
}
public class JoinABConfiguration : EntityTypeConfiguration<JoinAB>
{
public JoinABConfiguration()
{
HasKey(x => new { x.JKey, x.KKey });
}
}
public class Number1Context : DbContext
{
public DbSet<EntityA> EntityAs { get; set; }
public DbSet<EntityB> EntityBs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new JoinABConfiguration());
modelBuilder.Configurations.Add(new EntityAConfiguration());
modelBuilder.Configurations.Add(new EntityBConfiguration());
}
}
情况2:两个实体EntityC和EntityD仍处于多对多关系中,但连接表未使用类建模,并且EntityD没有EntityC的导航属性。这种情况类似于this post或this other post。
以下代码有效,唯一的问题是我无法为EntityD和连接表之间的关系禁用“on delete cascade”选项。有没有办法实现这一点,还是我被迫向EntityD添加导航属性?
public class EntityC
{
[Key]
public Int64 PK { get; set; }
public string Description { get; set; }
public List<EntityD> TheDEntities { get; set; }
public EntityC()
{
TheDEntities = new List<EntityD>();
}
}
public class EntityD
{
[Key]
public Int64 PK { get; set; }
public string SomeData { get; set; }
}
public class EntityCConfiguration : EntityTypeConfiguration<EntityC>
{
public EntityCConfiguration()
{
HasMany(x => x.TheDEntities).WithMany().Map(map =>
{
map.MapLeftKey("C_Key");
map.MapRightKey("D_Key");
map.ToTable("CustomJoinCDTable");
});
}
}
public class Number2Context : DbContext
{
public DbSet<EntityC> EntityCs { get; set; }
public DbSet<EntityD> EntityDs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new EntityCConfiguration());
}
}
案例3:两个实体EntityJ和EntityK处于多对多关系中,连接表使用类JoinJK显式建模(如案例1中所示),但实体K没有导航属性加入JK(如案例2)。
有没有办法让这个案子有效?我尝试了以下代码,但它不起作用,它抱怨“类型中的每个属性名称必须是唯一的。属性名称'KKey'已经定义。”。有没有办法告诉实体框架“KKey”是主键的两部分,也是EntityK的外键,没有在EntityK中放置“List”导航属性?
(我们的想法是EntityK被许多其他实体引用,我们不希望它与许多导航属性混淆)。
public class EntityJ
{
[Key]
public Int64 PK { get; set; }
public string Description { get; set; }
public List<JoinJK> TheKEntities { get; set; }
public EntityJ()
{
TheKEntities = new List<JoinJK>();
}
}
public class EntityK
{
[Key]
public Int64 PK { get; set; }
public string SomeData { get; set; }
}
public class JoinJK
{
public Int64 JKey { get; set; }
public Int64 KKey { get; set; }
public EntityJ EntityJ { get; set; }
public EntityK EntityK { get; set; }
}
public class EntityJConfiguration : EntityTypeConfiguration<EntityJ>
{
public EntityJConfiguration()
{
HasMany(x => x.TheKEntities).WithRequired(y => y.EntityJ).HasForeignKey(y => y.JKey).WillCascadeOnDelete(true);
}
}
public class JoinJKConfiguration : EntityTypeConfiguration<JoinJK>
{
public JoinJKConfiguration()
{
HasKey(x => new { x.JKey, x.KKey });
HasRequired(x => x.EntityK).WithRequiredDependent().Map(m => m.MapKey("KKey") ).WillCascadeOnDelete(false);
}
}
public class Number3Context : DbContext
{
public DbSet<EntityJ> EntityJs { get; set; }
public DbSet<EntityK> EntityKs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new JoinJKConfiguration());
modelBuilder.Configurations.Add(new EntityJConfiguration());
}
}
请注意,案例3的行为不依赖于不遵循实体框架命名约定的这些类。如果我创建一个与案例3相同的案例4,但遵循命名约定的类EntityV和EntityW,它无论如何都不起作用。实体框架不会使JoinVW中的“EntityWId”成为外键,它会在JoinVW中创建一个新列“EntityW_Id”作为外键。 (如果我将我的密钥命名为“EntityWId”,它会忽略它,并在数据库中创建“EntityW_Id1”。
public class EntityV
{
public Int64 Id { get; set; }
public string Description { get; set; }
public List<JoinVW> TheWEntities { get; set; }
public EntityV()
{
TheWEntities = new List<JoinVW>();
}
}
public class EntityW
{
public Int64 Id { get; set; }
public string SomeData { get; set; }
}
public class JoinVW
{
public Int64 EntityVId { get; set; }
public Int64 EntityWId { get; set; }
public EntityV EntityV { get; set; }
public EntityW EntityW { get; set; }
}
public class EntityVConfiguration : EntityTypeConfiguration<EntityV>
{
public EntityVConfiguration()
{
HasMany(x => x.TheWEntities).WithRequired(y => y.EntityV).HasForeignKey(y => y.EntityVId).WillCascadeOnDelete(true);
}
}
public class JoinVWConfiguration : EntityTypeConfiguration<JoinVW>
{
public JoinVWConfiguration()
{
HasKey(x => new { x.EntityVId, x.EntityWId });
HasRequired(x => x.EntityW).WithRequiredDependent().WillCascadeOnDelete(false);
}
}
public class Number4Context : DbContext
{
public DbSet<EntityV> EntityVs { get; set; }
public DbSet<EntityW> EntityWs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new JoinVWConfiguration());
modelBuilder.Configurations.Add(new EntityVConfiguration());
}
}
提前谢谢
德梅特里奥
编辑(愚蠢的我)
好的,我的代码中有关于案例3和案例4的错误。错误的行是:
HasRequired(x => x.EntityK).WithRequiredDependent().Map(m => m.MapKey("KKey") ).WillCascadeOnDelete(false);
正确的行应该是:
HasRequired(x => x.EntityK).WithMany().HasForeignKey(zz => zz.KKey).WillCascadeOnDelete(false);
使用此代码,案例3和案例4正常工作,所以我回答了我自己关于案例3/4的问题(“有没有办法告诉实体框架”KKey“是主键的两部分AND也是EntityK的外键,没有在EntityK中放置“List”导航属性?“。是的,有,并且是WithMany().HasForeignKey
)。
但是我仍然找不到案例2的答案:在这种情况下如何禁用“删除级联”?
在所有四种情况下我注意到的另一件事:实体框架总是为连接表生成三个索引:第一个在密钥上,第二个在另一个密钥上,第三个是PK强制执行索引,集群唯一两个键上的索引。但是如果我想让其中一个索引聚集呢?单个键上的两个非聚簇索引之一是冗余的:例如,如果有一个聚簇索引(AKey,BKey),那么BKey上的非聚簇索引将是有用的,但AKey上的非聚簇索引将是无用的,因为群集一个(AKey,BKey)可以做同样的工作。