EF Code First自引用多对多...在抽象或派生类上

时间:2012-02-02 17:42:18

标签: entity-framework-4.1 ef-code-first wcf-data-services

我正在尝试使用多态表结构在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模型?

0 个答案:

没有答案