具有通用对象类型的流畅API复合外键

时间:2012-05-02 14:24:15

标签: entity-framework entity-framework-4.1 ef-code-first fluent-interface

我有一个Organization类和一个User类,如下所示,&我希望能够为每个人单独分配一个地址 - 而不需要为AddressUser& amp;而不需要两个单独的多对多表。 AddressOrganization,AddressAnything等。原因是我可能有多个实体,我想分配一个地址到&不希望每个需要地址记录的实体都有一个中间连接表。

我也不想为需要与之关联的地址的每个实体存储Address.OrganizationId或Address.UserId等外键。

Fluent API或Code-First Data Annotations是否可以容纳某种具有对象类型的复合通用外键?

与DomainObjectType表类似吗?

DomainObjectType:

public class DomainObjectType
{
    [Key]
    public int Id { get; set; } // seeded

    public string ObjectType { get; set; } // User or Organization
}

DomainObjectType将以:

播种
var objTypes = new List<DomainObjectType>
  { 
      new DomainObjectType() { Id = 1, ObjectType = "User" },
      new DomainObjectType() { Id = 2, ObjectType = "Organization" }
  };
objTypes.ForEach(c => context.DomainObjectTypes.Add(c));
context.SaveChanges();

组织:

public class Organization
    {    
        // Primary key
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        #region Navigation Properties

        public virtual ICollection<User> Users { get; set; }
        public virtual ICollection<Address> Addresses { get; set; }

        #endregion

    }

用户

public class User
{
    [Key]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int OrganizationId { get; set; }

    [ForeignKey("OrganizationId")]
    public virtual Organization Organization { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
}

地址

public class Address
{
    // Primary Key
    public int Id { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
    public string AddressType { get; set; }

    #region Foreign Keys

    // not completely sure about this? (maybe move to many-to-many "join" table)
    public int DomainObjectId { get; set; } // Composite key; would be either an OrganizationId or UserId
    public string DomainObjectTypeId { get; set; } // Composite key

    #endregion

    #region Navigation Properties

    public virtual ICollection<Organization> Organizations { get; set; }
    public virtual ICollection<User> Users { get; set; }

    #endregion

}

流畅的API内容:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Configure Code First to ignore PluralizingTableName convention
        // If you keep this convention then the generated tables will have pluralized names.
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        // one-to-many Organization-to-Users
        modelBuilder.Entity<User>()
            .HasRequired(u => u.Organization)
            .WithMany(o => o.Users)
            .HasForeignKey(u => u.OrganizationId);

        // what goes here for generic AddressDomainObjectType?
    }

1 个答案:

答案 0 :(得分:1)

您可以实现您想要的目标 - 在Address和&#34;其他实体之间只有一个多对多表格&#34; - 为那些&#34;其他实体&#34;创建一个基类,例如:

public abstract class DomainObjectWithAddresses
{
    public int Id { get; set; }

    public virtual ICollection<Address> Addresses { get; set; }
}

public class User : DomainObjectWithAddresses
{
    // other properties but without Id which is inherited from base class
}

public class Organization : DomainObjectWithAddresses
{    
    // other properties but without Id which is inherited from base class
}

public class Address
{
    public int Id { get; set; }
    // other properties

    public virtual ICollection<DomainObjectWithAddresses> DomainObjects
                                                                 { get; set; }
}

使用Fluent API进行映射:

modelBuilder.Entity<DomainObjectWithAddresses>()
    .HasMany(d => d.Addresses)
    .WithMany(a => a.DomainObjects)
    .Map(x =>
    {
        x.ToTable("DomainObjectAddresses");
        x.MapLeftKey("DomainObjectId");
        x.MapRightKey("AddressId");
    });

modelBuilder.Entity<User>()
    .ToTable("Users");           // TPT inheritance mapping

modelBuilder.Entity<Organization>()
    .ToTable("Organizations");   // TPT inheritance mapping

您的DbContext基本类型为DbSet

public DbSet<DomainObjectWithAddresses> DomainObjects { get; set; }

我不喜欢它。我更愿意为与地址有多对多关系的每种类型引入多个连接表。我怀疑在域模型中引入抽象只是为了在数据库中保存一些表是一个好主意。这个抽象的DomainObjectWithAddresses类是一个非常技术性的(&#34; table-savings-helper&#34;)工件,在您的域模型中没有任何重要意义。对我来说,用户拥有地址和组织拥有地址而不是说用户 是一个对象时,听起来更自然地址和组织具有地址的对象。从长远来看,这只会使您的模型变得复杂。