将多个表与实体框架代码中的单个通用表相关联 [英] Relate Multiple Tables to Single General Purpose Table in Entity Framework Code First

查看:109
本文介绍了将多个表与实体框架代码中的单个通用表相关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很多时候,我有一个通用实体,其他实体包含一个集合。我不想为需要它但需要重新使用单个通用实体的每个父实体类型都有一个新的集合实体。出于性能原因,我也不想在此答案中明确定义多对多关系。最简单的例子是字符串集合。

  public class MyString 
{
public Guid Id {得到;组; }
public string Value {get;组; }
}

public class MyEntity
{
public Guid Id {get;组; }
public virtual List< MyString> {get;组; }
}

public class MyOtherString
{
public Guid Id {get;组; }
public string Value {get;组; }
}

public class MyOtherEntity
{
public Guid Id {get;组; }
public virtual List< MyOtherString> {get;组; }
}

我真的想结合 MyString MyOtherString 成一个实体:

  public class GeneralPurposeString 
{
public Guid Id {get;组; }
public string Value {get;组; }
}

public class MyEntity
{
public Guid Id {get;组; }
public virtual List< GeneralPurposeString> {get;组; }
}

public class MyOtherEntity
{
public Guid Id {get;组; }
public virtual List< GeneralPurposeString> {get;组; }
}

除了现在我要在<$包含 GeneralPurposeString 的每个实体的c $ c> GeneralPurposeString 。



我想要的方法是在 GeneralPurposeString 表(但不是实体)上指定该项目所属的实体的另一个父类别列。我使用 Guid 为主键,所以表可能看起来像这样:

  CREATE TABLE [GeneralPurposeString] 

[Id] uniqueidentifier NOT NULL
CONSTRAINT PK_GeneralPurposeString PRIMARY KEY,
[ParentEntityCategory] ​​uniqueidentifier NOT NULL,
[ParentEntityId] uniqueidentifier NOT NULL,
[Value] nvarchar(MAX)

一些如何在Code First中指定 MyEntity 有一个特定的类别,而且它的集合 GeneralPurposeString 使用该类别,和 MyOtherEntity 使用另一个类别(Guid)为 GeneralPurposeString 的集合。



关键是 GeneralPurposeString 可以是任何其他实体的集合,加载父实体并包含集合将自动加载而不必明确指定的类别。



所有这些的目的是


  1. 允许.NET代码拥有 GeneralPurposeString 无法复制的代码(实际实用程序或业务逻辑代码)。这可能还可以通过继承和显式映射来实现,但仍然会在数据库中留下多个表(参见#2)。

  2. 数据库中只有一个表 GeneralPurposeString 。这更是一个整洁的问题。性能可能会更好与多个表,但索引在 ParentEntityCategory / ParentEntityId 并覆盖应该是查询的良好性能。

  3. 不必显式地对这种关系进行编码,并且需要在任何地方查找。


解决方案

我在想,如果我可以超越#2,并在幕后使用一个单独的表,并实现一个派生类,那么将是最简单的路线。



所以只是:

  public class GeneralPurposeString 
{
public Guid Id {get;组; }
public string Value {get;组; }
}

//这只是一个泛型的MyEntity会员引脚的一个GeneralPurposeString
public class MyEntityString:GeneralPurposeString {}

public class MyEntity
{
public Guid Id {get;组; }
public virtual List&MyEntityString>字符串{get;组;
}

// Cool GeneralPurposeStrings属于MyOtherEntity
public class MyOtherEntityString:GeneralPurposeString {}

public class MyOtherEntity
{
public Guid Id {get;组; }
public virtual List< MyOtherEntityString>字符串{get;组; }
}

public class MyContext:DbContext
{
public DbSet< MyEntity>新新旗新新旗新新旗旗新新旗旗新新旗人1992:组; }
public DbSet< MyOtherEntity> MyOtherEntities {get;组;
}

我不必将派生类添加到 DbContext ,默认情况下,这些表命名为派生类的复数,所以实际上很简单。



我以前的即使EF支持,父母类别的思路也需要额外的编码/注释。这使用纯粹的惯例,在注释或 OnModelCreating()



我没有看到任何在这个时间点额外的桌子伤害。我没有看到需要(目前)将一个表中的所有数据都用于报告,但这真的取决于通用实体的类型,所以我可能需要在将来重新访问,或者我可能会采取如果我需要一个表格中的数据,那么多对多路由。



我还可以:



公共静态类GeneralPurposeStringExtensions
{
public static void SassThatHoopyFrood(this GeneralPurposeString s)
{
// do stuff
}
}


Many times I have a general purpose entity that other entities contain a collection of. I don't want to have a new collection entity for each parent entity type that needs it but would like to re-use a single general purpose entity. For performance reasons, I also don't want to explicitly define many-to-many relationships as in this answer. The simplest example would be a collection of strings.

public class MyString
{
    public Guid Id { get; set; }
    public string Value { get; set; }
}

public class MyEntity
{
    public Guid Id { get; set; }
    public virtual List<MyString> { get; set; }
}

public class MyOtherString
{
    public Guid Id { get; set; }
    public string Value { get; set; }
}

public class MyOtherEntity
{
    public Guid Id { get; set; }
    public virtual List<MyOtherString> { get; set; }
}

I'd really like to combine MyString and MyOtherString into a single entity:

public class GeneralPurposeString
{
    public Guid Id { get; set; }
    public string Value { get; set; }
}

public class MyEntity
{
    public Guid Id { get; set; }
    public virtual List<GeneralPurposeString> { get; set; }
}

public class MyOtherEntity
{
    public Guid Id { get; set; }
    public virtual List<GeneralPurposeString> { get; set; }
}

Except now I'm going to have an additional foreign key in GeneralPurposeString for every entity that contains a collection of GeneralPurposeString.

What I would like would be a way to have an additional parent category column on the GeneralPurposeString table (but not the entity) that would specify which entity the item belongs to. I use Guid for primary keys, so the tables could look something like this:

CREATE TABLE [GeneralPurposeString]
(
    [Id] uniqueidentifier NOT NULL 
         CONSTRAINT PK_GeneralPurposeString PRIMARY KEY,
    [ParentEntityCategory] uniqueidentifier NOT NULL,
    [ParentEntityId] uniqueidentifier NOT NULL,
    [Value] nvarchar(MAX)
)

And some how in Code First to specify that MyEntity has a certain category, and that it's collection of GeneralPurposeString uses that category, and MyOtherEntity uses another category (Guid) for it's collections of GeneralPurposeString.

The key would be that GeneralPurposeString could be a collection in any other entity and that loading the parent entity and including the collection would automatically load without having to explicitly specify the category.

The purposes for all of this are

  1. Allow .NET code to have GeneralPurposeString code that wasn't replicated everywhere (actual utility or business logic code). This can probably also be accomplished through inheritance and explicit mapping but that would still leave multiple tables in the database (see #2).
  2. Have only one table in the database for GeneralPurposeString. This is more of a tidiness issue. Performance would possibly be better with multiple tables, but indexing on ParentEntityCategory/ParentEntityId and covering Value should be good performance for lookups.
  3. Not have to explicitly code this relationship and the lookups everywhere it's needed.

解决方案

I'm thinking if I can get over #2 and be OK with a separate table behind the scenes and implementing a derived class, that will be the simplest route to go.

So just:

public class GeneralPurposeString
{
    public Guid Id { get; set; }
    public string Value { get; set; }
}

// It's just a GeneralPurposeString with a fancy MyEntity membership pin
public class MyEntityString: GeneralPurposeString {}

public class MyEntity
{
    public Guid Id { get; set; }
    public virtual List<MyEntityString> Strings { get; set; }
}

// Cool GeneralPurposeStrings belong to MyOtherEntity
public class MyOtherEntityString: GeneralPurposeString {}

public class MyOtherEntity
{
    public Guid Id { get; set; }
    public virtual List<MyOtherEntityString> Strings { get; set; }
}

public class MyContext: DbContext
{
    public DbSet<MyEntity> MyEntities { get; set; }
    public DbSet<MyOtherEntity> MyOtherEntities { get; set; }
}

I don't have to add the derived classes to the DbContext and the tables get named with the plural of the derived class by default, so it's actually pretty straight forward.

My previous train of thought with the Parent Category would require additional coding/annotation even if EF supported it. This uses purely convention and nothing extra needed in annotations or in OnModelCreating().

I'm not seeing any harm in extra tables at this point in time. I don't see a need (currently) to have all of the data in one table for reporting, but that really depends on the type of general purpose entity, so I may need to revisit this in the future, or I may just take the many-to-many route if I do need the data in one table.

And I can still have:

public static class GeneralPurposeStringExtensions
{
    public static void SassThatHoopyFrood(this GeneralPurposeString s)
    {
        // do stuff
    }
}

这篇关于将多个表与实体框架代码中的单个通用表相关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆