4

实体框架中是否有一种方法(我假设它将使用流畅的语法,因为数据注释在一定程度上受到限制)来建模双方都是可选的多对多关系(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 类(相当于用户)。作者和标签是 1:M,实体的作者也是 1:M。所以当然,问题在于 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 在这个表上可以为空。也许这个模型没有我想象的那么有意义??你能有一个两边都可以为空的桥接表吗?

4

2 回答 2

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);
于 2013-01-14T03:50:46.380 回答
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>();

获取特定的实体集。

于 2013-01-17T17:45:51.167 回答