使用自定义键名映射通用多对多

Posted

技术标签:

【中文标题】使用自定义键名映射通用多对多【英文标题】:Mapping generic Many-Many with custom key names 【发布时间】:2018-08-13 13:43:19 【问题描述】:
public class Entity1

    public int Id  get; set; 
    public Guid EntityKey  get; set; 
    public ICollection<Entity2> Entity2s  get; set; 


public class Entity2

    public int Id  get; set; 
    public Guid EntityKey  get; set; 


public class EntityMapping 

    public int Id  get; set; 
    public Guid ParentKey  get; set; 
    public EntityType ParentType  get; set; 
    public Guid ChildKey  get; set; 
    public EntityType ChildType  get; set; 

我需要使用 fluent 配置 API 做一些事情来执行:

select e2.* from Entity1 e1
join Entitymapping em on em.ParentKey == e1.EntityKey && em.ParentType == 'Entity1'
join Entity2 e2 on em.ChildKey == e2.EntityKey

当我打电话时:entity1.Entity2s.ToList()

仅使用 EF 4 中的 fluent 配置是否也能做到这一点?

【问题讨论】:

【参考方案1】:

好的,首先。为什么不使用 Id 字段作为主要字段?由 SQL Server 维护为唯一的,等等。每个实体有两个键正在自找麻烦。

与我给here的MM答案几乎相同

您的实体需要一些工作。 Entity1/Entity2 导航属性应指向 List 并且 EntityMapping 应指向 Entity1 和 Entity2 中的每一个。这是一个 1-1 的连接表,其中每一边都可以有很多,因此是多对多。如果您希望所有 Entity1 及其关联的 Entity2 更像这样:

DbSet.Entity1.Include("EntityMapping").Include("EntityMapping.Entity2").ToList();

使用单个表来存储许多不同实体之间的关系仍然可以使用类似的结构。将有一些“幕后”检查来强制 1-1 或 1-M 关系进入 M-M 模式,打赌这应该让你开始......

public class Entity1

    public int Id  get; set; 
    public Guid EntityKey  get; set; 
    public EntityType E1Type  get; set; 
    public ICollection<EntityMapping> Entity2s  get; set; 


public class Entity2

    public int Id  get; set; 
    public Guid EntityKey  get; set; 
    public EntityType E2Type  get; set; 
    public ICollection<EntityMapping> Entity1s  get; set; 


public class EntityMapping 

    public int Id  get; set; 
    public int ParentKey  get; set; 
    public int ChildKey  get; set; 
    public Entity1 Entity1  get; set; 
    public Entity2 Entity2  get; set; 

对于所有名为“Foo”的实体和“Bar”子实体(假设 Foo 也可能与“Widgets”相关,有一种 EF“方式”可以做到这一点,但您要使用的 SQL SELECT 是

select e1.EntityKey as e1Key, e2.EntityKey as e2Key from Entity1 e1
inner join EntityMapping e3 on e3.ParentKey = e1.Id
inner join Entity2 e2 on e2.Id = e3.ChildKey
where e1.E1Type = "Foo" and e2.E2Type = "Bar"

EF 说话

var temp = DbSet.Entity1.Select(p => p.E1Type == "Foo").Include("EntityMapping").Include("EntityMapping.Entity2");
var result = temp.Where(r => r.E2Type == "Bar").ToList();

可能可以将这些结合起来,但我必须修补而不是“即兴发挥”。那更好吗?

【讨论】:

EF 加载参考更像 DbSet.Entity2.ToList()。 它没有使用主要的,因为这个映射表正在被许多不同类型的实体重用 好的,所以 Guid 只是数据,而不是键。因此不要在关系中使用。例子是准确的。 思考:或者您是说有许多不同的 Entity1/Entity2 表共享此连接方法? 这是一个庞大的遗留应用程序,我们不得不将我们的地址抽象为“空间”。我们可以通过我们的存储库访问所有内容,但是直接在 Domain 类中引用类型并让配置处理连接会更好。底线是我们的架构看起来是这样的,我只需要知道这是否可以通过 fluent API 实现。我不在乎它是否“正确”...

以上是关于使用自定义键名映射通用多对多的主要内容,如果未能解决你的问题,请参考以下文章

Python学习---django多对多自定义第三方表180206

多对多自引用关系

Sequelize 多对多自引用

多对多自引用表

带有额外列的多对多自引用原则

sqlalchemy中的多对多自引用关系