0

我有一个组织类和一个用户类,如下所示,并且我希望能够为每个单独分配一个地址 - 不需要两个单独的多对多表用于 AddressUser 和 AddressOrganization、AddressAnything 等。原因是我可能有多个实体,我想为其分配一个地址,并且不希望每个需要地址记录的单个实体都有一个中间连接表。

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

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

像 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?
    }
4

1 回答 1

1

您可以通过为这些“其他实体”创建一个基类来实现您想要的 - 在“其他实体”和“其他实体”之间只有一个多对多表Address,例如:

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类是一个非常技术性的(“table-savings-helper”)工件,在您的领域模型中没有任何价值。对我来说,说一个用户有地址,一个组织地址,而不是说一个用户一个有地址的对象,一个组织一个有地址的对象,这听起来要自然得多。从长远来看,这只会使您的模型变得复杂。

于 2012-05-02T21:49:40.857 回答