是否有一种方法来建模一个可选的多对多关系在实体框架

本文关键字:框架 关系 实体 一种 方法 是否 建模 一个 | 更新日期: 2023-09-27 17:53:02

在实体框架中是否有一种方法(我认为它将具有流利的语法,因为数据注释有些有限)来建模多对多关系,其中双方都是可选的(0..从M到0…N关系)?用例是这样的:我希望允许用户向实体添加标记。标签到实体是一个M:N关系,但两者都不是必需的。也就是说,一个标签可以存在而不应用于任何实体,一个实体可以被取消标签。这在我看来相当合理。我不能简单地使用:

public virtual ICollection<Tag> Tags { get; set; }

public virtual ICollection<Entity> Entities { get; set; }

,因为每个类都有其他关系,我得到一个"外键约束可能导致循环或多个级联路径"。我希望也许我可以这样做:

modelBuilder.Entity<Tag>().HasOptional(t => t.Entities);
modelBuilder.Entity<Entity>().HasOptional(t => t.Tags);

但是我被警告EF是"无法确定关联的主要端"。从阅读来看,这种关系似乎必须有一个主要目的,但对我来说,这是不可取的。

我可以添加一个类来表示桥表并手动处理映射,但我不希望使代码混乱。我想知道是否有另一种方法在EF中建模。

为了更详细地说明,这里还有一个Author类(相当于Users)。作者和标签是1:1,作者到实体也是1:1。当然,问题是Entities类在级联树中出现了两次。将标签/实体关系设为可选将解决这个问题。如果有一种方法可以通过实体访问标签,我也可以修复它,但由于标签可以在不连接到实体的情况下存在,我认为这是不可能的。

下面是相关代码的摘要:

public class Author
{
    public Guid Id { get; set; }
    public virtual List<Entity> Entities { get; set; }
    public virtual List<Tag> Tags { get; set; }
}
public class Tag
{
    public Guid Id { get; set; }
    public Guid AuthorId { get; set; }
    public virtual Author Author { get; set; }
    public virtual ICollection<Entity> Entities { get; set; }
}
public class Entity
{
    public Guid Id { get; set; }
    public Guid AuthorId { get; set; }
    public virtual Author Author { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
}
编辑:

使用.HasMany().WithMany(),如下所示:

CREATE TABLE [dbo].[TagEntities] (
    [Tag_Id] [uniqueidentifier] NOT NULL,
    [Entity_Id] [uniqueidentifier] NOT NULL,
    CONSTRAINT [PK_dbo.TagEntities] PRIMARY KEY ([Tag_Id], [Entity_Id])
)

但是我想要的是Tag_Id和Entity_Id在这个表上是空的。也许这个模型没有我想的那么有意义??你能有一个两边都为空的桥表吗?

是否有一种方法来建模一个可选的多对多关系在实体框架

使用

modelBuilder.Entity<Tag>().HasMany(t => t.Entities)
    .WithMany(t => t.Tags);
不是

modelBuilder.Entity<Tag>().HasOptional(t => t.Entities);
modelBuilder.Entity<Entity>().HasOptional(t => t.Tags);

我不知道这是否是正确的答案,但我通过创建一个名为DbEntity的基类来解决这个问题,其他类继承了它。现在Author只需要:

// Both entities and tags are part of this collection
public virtual List<DbEntity> Entities { get; set; }

"实体"(在我的代码中有特殊的含义)和"标签"子类DbEntity。这在保留导航属性的同时消除了多个级联路径,尽管我确实需要这样做:

author.Entities.OfType<Tag>();

author.Entities.OfType<Entity>();