实体之间的通用属性表

时间:2012-06-29 13:46:27

标签: c# entity-framework ef-code-first

以下是使用EF 5.0.0-rc和Code First。在我的设计中,我有一个属性实体:

public class Attribute
{ 
    public int AttributeId { get; set; }
    public Guid Guid { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }

    /* Used for testing the first fluent statement */
    public virtual ICollection<Customer> Customers { get; set; }
}

我还有多个包含GUID的实体:

public class Customer
{ 
    public int CustomerId { get; set; }
    public Guid Guid { get; set; }
}

public class Location
{ 
    public int LocationId { get; set; }
    public Guid Guid { get; set; }
}

我希望属性表对于客户和位置表都是通用的,中间没有列或表。我似乎无法在流畅的API中获得正确的映射来创建没有辅助表的FK:

        modelBuilder.Entity<Customer>()
            .HasMany(o => o.Attributes)
            .WithMany(o => o.Customers)
            .Map(m => m.MapLeftKey("Guid"));

...将生成一个不应该需要的CustomerAttributes表。

        modelBuilder.Entity<Organization>()
            .HasMany(o => o.Attributes)
            .WithOptional()
            .HasForeignKey(o => o.Guid);

...不会编译,因为

  

参照约束的从属角色中的所有属性的类型必须与主体角色中的相应属性类型相同。

如何建立关系?或者设计不合适?

编辑:成功!

在RaphaëlAlthaus的指导下,我准备好了EF的方式,为每个实体提供单独的跟踪表,但他建议创建一个Cust和Loca实体将继承的新类的建议让我朝着正确的方向前进。

首先,我创建了一个“父”类,这也让我有机会重构一些存储在大多数实体上的审计数据:

public class ParentEntity
{
    [Key]
    public Guid Guid { get; set; }

    public DateTime? CreatedOn { get; set; }
    public string CreatedBy { get; set; }
    public DateTime? ModifiedOn { get; set; }
    public string ModifiedBy { get; set; }

    [Timestamp]
    public byte[] Version { get; set; }

    public virtual ICollection<Attribute> Attributes { get; set; }
}

然后我继承了Cust和Loca实体上的父类:

public class Customer : ParentEntity
{ 
    public int CustomerId { get; set; }
    public Guid Guid { get; set; }
}

public class Location : ParentEntity
{ 
    public int LocationId { get; set; }
    public Guid Guid { get; set; }
}

我还修改了Attribute类以支持新的FK字段EntityGuid:

public class Attribute
{
    public int AttributeId { get; set; }
    public Guid EntityGuid { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

这给了我几乎所有我需要的东西,除了......它试图将每个实体存储在新的ParentEntity表中。解决我使用过的问题:

        modelBuilder.Entity<Customer>().ToTable("Customers");
        modelBuilder.Entity<Location>().ToTable("Locations");

最后是将这一切结合在一起的作品:

        modelBuilder.Entity<ParentEntity>()
            .HasMany(e => e.Attributes)
            .WithRequired()
            .HasForeignKey(e => e.EntityGuid);

我能说的唯一缺点是ParentEntity接管主键,即Guid。但我保留了其他密钥,并计划将其用作聚类索引。

1 个答案:

答案 0 :(得分:0)

您的混合对象世界和rDBMS世界。

你在ORM中,所以你不应该介意(好吧,不是完整的,但在这种情况下,是的)你的数据库中真正存在的是什么。

如果没有“链接”(关系)表,rDBMS无法管理多对多的关系(如何表示作为列表的外键?不可能没有关系表)。

在对象世界中,List<x>中的yList<y>中的x可以做到这一点,而没有任何“关系”实体。

修改

如果您想要一个共同的“关系”表,您可以创建一个新实体(使用Guid):客户和位置将从该新实体继承,并且属性实体将与该新实体链接。