我正在尝试使用多态表结构在EF CodeFirst中对多个自引用进行建模。我正在使用2011年10月的CTP,它支持派生类型的导航属性(在我完成的其他测试中效果很好)。
问题:
当我在基本(抽象)表的映射中设置这个特定的多对多关系并尝试获取相关记录时,我得到一个包含数百K个联合和联接的SQL查询...只是生成所需的时间SQL语句是30秒,而执行它只需要几毫秒。但是,它确实返回了适当的结果。当我在两个派生对象之间更改多个到多个时,生成的查询是完美的...但我不能再为其他派生对象映射相同的相关M2M表,而不会被告知连接表已经“已经映射”
具体细节:
现有的数据库结构有一个基表 - Party - 与Customer,Vendor,User和Department(每种类型的Party)连接1 ... 1或0。
各方通过现有的联接表PartyRelationship(ID,InternalPartyID,ExternalPartyID)相互关联。按照惯例,InternalPartyID包含用户的PartyID,ExternalPartyID包含与之关联的客户,供应商或部门的PartyID。
尝试在新项目(WCF DataServices)中使用EF CodeFirst,我创建了Party类:
public abstract class Party
{
public Party()
{
this.Addresses = new List<Address>();
this.PhoneNumbers = new List<PhoneNumber>();
this.InternalRelatedParties = new List<Party>();
this.ExternalRelatedParties = new List<Party>();
}
public int PartyID { get; set; }
public short Active { get; set; }
//other fields common to Parties
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
public virtual ICollection<Party> InternalRelatedParties { get; set; }
public virtual ICollection<Party> ExternalRelatedParties { get; set; }
}
然后,使用TPT继承,客户,供应商,部门和用户类似于:
public class Customer : Party
{
public string TermsCode { get; set; }
public string DefaultFundsCode { get; set; }
//etc
}
public class User : Party
{
public string EmployeeNumber { get; set; }
public string LoginName { get; set; }
//etc
}
加入表:
public class PartyRelationship
{
public int PartyRelationshipID { get; set; }
public int InternalPartyID { get; set; }
public int ExternalPartyID { get; set; }
//certain other fields specific to the relationship
}
映射:
public class PartyMap : EntityTypeConfiguration<Party>
{
public PartyMap()
{
// Primary Key
this.HasKey(t => t.PartyID);
// Properties
this.ToTable("Party");
this.Property(t => t.PartyID).HasColumnName("PartyID");
this.Property(t => t.Active).HasColumnName("Active");
//etc
// Relationships
this.HasMany(p => p.InternalRelatedParties)
.WithMany(rp => rp.ExternalRelatedParties)
.Map(p => p.ToTable("PartyRelationship")
.MapLeftKey("ExternalPartyID")
.MapRightKey("InternalPartyID"));
}
}
public class PartyRelationshipMap : EntityTypeConfiguration<PartyRelationship>
{
public PartyRelationshipMap()
{
// Primary Key
this.HasKey(t => t.PartyRelationshipID);
// Properties
// Table & Column Mappings
//this.ToTable("PartyRelationship"); // Commented out to prevent double-mapping
this.Property(t => t.PartyRelationshipID).HasColumnName("PartyRelationshipID");
this.Property(t => t.InternalPartyID).HasColumnName("InternalPartyID");
this.Property(t => t.ExternalPartyID).HasColumnName("ExternalPartyID");
this.Property(t => t.CreateTime).HasColumnName("CreateTime");
this.Property(t => t.CreateByID).HasColumnName("CreateByID");
this.Property(t => t.ChangeTime).HasColumnName("ChangeTime");
this.Property(t => t.ChangeByID).HasColumnName("ChangeByID");
}
}
上下文:
public class MyDBContext : DbContext
{
public MyDBContext()
: base("name=MyDBName")
{
Database.SetInitializer<MyDBContext>(null);
this.Configuration.ProxyCreationEnabled = false;
}
public DbSet<Party> Parties { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
modelBuilder.Configurations.Add(new PartyMap());
modelBuilder.Configurations.Add(new PartyRelationshipMap());
}
}
诸如http://localhost:29004/Services/MyDataService.svc/Parties(142173)/SAData.Customer/InternalRelatedParties之类的URL最终会返回正确的oData,但需要30秒才能生成在600毫秒内执行的巨大SQL语句(189K)。
我也尝试将PartyRelationship表映射为双向的一对多(都作为“一个”表的Party),但结果相似。
我是否需要为客户 - 用户,供应商 - 用户和部门 - 用户提供单独的连接表?我应该查看将PartyRelationship分离为单独的逻辑实体的垂直表拆分或数据库视图(因此我可以重新映射同一个表)?在这种情况下是否应该采用另一种方式配置EF模型?