简体   繁体   English

在“代码优先”方法中定义“多个表到一个表”的关系

[英]Define Many Tables to One Table relationship in Code First approach

I am in the process of building up a data model in Entity Framework using the Code First approach, but one part has me a bit stumped. 我正在使用“代码优先”方法在Entity Framework中建立数据模型,但是有一部分让我有些困惑。 The title on this question may be a bit confusing, so I will explain my problem in detail. 这个问题的标题可能有点令人困惑,因此我将详细解释我的问题。 The length of this post may be daunting, but I think it's a fairly straightforward problem. 这篇文章的篇幅可能令人生畏,但我认为这是一个相当简单的问题。

I have one model defined like this: 我有一个这样定义的模型:

public class KeyValuePair
{
    [Key]
    [MaxLength(128)]
    [Column(Order = 0)]
    public virtual string OwnerId { get; set; }

    [Key]
    [MaxLength(128)]
    [Column(Order = 1)]
    public virtual string Key { get; set; }

    public virtual string Value { get; set; }
}

My intent is for this to just define a generic table for storing key-value properties on other entities in the system. 我的目的是仅定义一个通用表,用于在系统中的其他实体上存储键值属性。 I am using GUIDs for all of my Ids, so OwnerId should uniquely refer to one entity in the system, and the pair (OwnerId, Key) should uniquely identify one property on one entity. 我为所有Id使用GUID,因此OwnerId应该唯一地引用系统中的一个实体,而对(OwnerId, Key)应该唯一地标识一个实体上的一个属性。

In other words, I want to allow multiple tables in my system to have a One->Many relationship to this KeyValuePair table. 换句话说,我想允许系统中的多个表与此KeyValuePair表具有“一对多”关系。

So for example, if I wanted to store the height of a Person who has the ID b4fc3e9a-2081-4989-b016-08ddd9f73db0 , I would store a row in this table as: 因此,例如,如果我要存储ID为b4fc3e9a-2081-4989-b016-08ddd9f73db0 ,我将在该表中存储以下行:

OwnerId = "b4fc3e9a-2081-4989-b016-08ddd9f73db0"
Key = "Height"
Value = "70 in."

So now I want to define navigation properties from the parent entities to this table, like (to take the Person example): 因此,现在我想定义从父实体到此表的导航属性,例如(以Person为例):

public class Person
{
    [Key]
    public virtual string Id { get; set; }

    public virtual string Name { get; set; }

    // I want this to be a navigation property
    public ICollection<KeyValuePair> Properties { get; set; }
}

But I'm not sure how do define the relationship between Person and KeyValuePair so that Entity Framework knows that it should look up the Person's properties by matching the Person 's Id against the KeyValuePair s' OwnerId . 但是我不确定如何定义PersonKeyValuePair之间的关系,以便实体框架知道它应该通过将PersonIdKeyValuePairOwnerId进行匹配来查找Person的属性。 I can't define a foreign key in the KeyValuePair model, because the OwnerId is going to refer to Ids in several different tables. 我无法在KeyValuePair模型中定义外键,因为OwnerId将在几个不同的表中引用ID。

It looks like I can do the following to define a relationship from Person to KeyValuePair in OnModelCreating : 看来我可以执行以下操作以在OnModelCreating定义从PersonKeyValuePairOnModelCreating

modelBuilder.Entity<Person>()
    .HasMany(p => p.Properties).WithMany().Map(mp =>
    {
        mp.MapLeftKey("Id");
        mp.MapRightKey("OwnerId", "Key");
        mp.ToTable("PersonDetail");
    });

Or I could even give the KeyValuePairs their own unique IDs, get rid of OwnerId , and do this: 或者,我什至可以给KeyValuePairs分配自己的唯一ID,摆脱OwnerId ,然后执行以下操作:

modelBuilder.Entity<Person>()
    .HasMany(p => p.Properties).WithMany().Map(mp =>
    {
        mp.MapLeftKey("Id");
        mp.MapRightKey("Id");
        mp.ToTable("PersonDetail");
    });

But both of these approaches involve the creation of an intermediary table to link the Person and KeyValuePair tables, and that seems like excessive overhead in terms of bloating my database schema and requiring more expensive JOINs to query the data. 但是,这两种方法都涉及到创建一个中间表来链接Person表和KeyValuePair表,这在使数据库架构膨胀和需要更昂贵的JOIN来查询数据方面似乎开销过大。

So is there a way to define the relationship such that I don't need to involve intermediary tables? 因此,有没有一种方法可以定义这种关系,而无需涉及中间表? Am I going about this database design the wrong way? 我会以错误的方式进行此数据库设计吗?

Side note: For anyone wondering why I am using this approach to define properties on my entities rather than simply adding fixed properties to the data model, I am using fixed properties in the data model where applicable, but the application I am building requires the ability to define custom properties at runtime. 附注:大家很奇怪,为什么我使用这种方法来定义我的实体特性,而不是简单地增加固定属性数据模型, 在哪里适用于数据模型中使用固定属性,但我开发的应用程序需要的能力在运行时定义自定义属性。 I also think this question is applicable to other potential scenarios where multiple tables have a One->Many relationship to a shared table. 我也认为此问题适用于多个表与共享表具有“一对多”关系的其他潜在情况。

The only way I can think of doing it (and I'll admit, this is not the best of ideas, but it will do what you're asking) would be to have any classes that need to have this relationship with KeyValuePair implement an abstract class that contains the fully implemented navigational property, as well as the ID field. 我能想到的唯一方法(我会承认,这不是最好的主意,但是它将满足您的要求)是让任何需要与KeyValuePair建立这种关系的类实现包含完全实现的导航属性以及ID字段的抽象类。 By "fully implemented" I don't mean an actual, mapped relationship; “完全实现”不是指实际的映射关系; I mean that it should use a DbContext to go out to the KeyValuePair table and actually grab the relevant properties given the ID. 我的意思是,它应该使用DbContext转到KeyValuePair表,并实际获取给定ID的相关属性。

Something like this: 像这样:

public abstract class HasKeyValuePairs
{
   [Key]
   public virtual string Id { get; set; }

   [NotMapped]
   public ICollection<KeyValuePair> Properties
   {
      get
      {
          using(var db = new DbContext())
          {
             return db.KeyValuePairs.Where(kvp => kvp.OwnerID == this.ID);
          }
      }
   }
}

Assuming you're using Lazy Loading (given that you're using the virtual keyword), there shouldn't be much extra overhead to doing it like this, since EF would have to go back to the database anyway to pick up the properties if you ever called for them. 假设您使用的是惰性加载(假设您使用的是virtual关键字),则这样做不会有太多额外的开销,因为如果发生以下情况,EF仍必须返回数据库以获取属性你曾经呼吁过他们。 You might need to have that return a List just to avoid any potential ContextDisposedException later on in your code, but that at least will get you up and running. 您可能需要返回一个List只是为了避免以后在代码中出现任何潜在的ContextDisposedException ,但这至少会使您启动并运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM