有没有办法在Entity Framework中建模可选的多对多关系?

时间:2013-01-14 03:42:15

标签: c# entity-framework

实体框架中是否有一种方法(我假设它将使用流畅的语法,因为数据注释有些限制)来建模多对多关系,其中双方都是可选的(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:M,作者与实体也是1:M。当然,问题是实体类在级联树中出现两次。使标记/实体关系可选将解决此问题。我还可以修复它,如果有办法通过实体获得标签,但由于标签可以存在而不连接到实体,我认为这是不可能的。

以下是相关代码的摘要:

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可以在此表上为空。也许这个模型没有像我想的那么有意义?你有一个双方都可以为空的桥牌桌吗?

2 个答案:

答案 0 :(得分:3)

使用

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);

答案 1 :(得分:0)

我不知道这是否是正确的答案,但我通过创建一个名为DbEntity的基类来解决这个问题,其他类继承自该类。所以现在作者刚刚:

// 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>();

获取特定的实体集。