【问题标题】:Entity Framework Many to Many works but Include does not实体框架多对多有效,但包含无效
【发布时间】:2013-03-11 11:18:11
【问题描述】:

我与这 3 个表有典型的多对多关系

[Post] (
  [PostId] int, (PK)
  [Content] nvarchar(max)
   ...
)

[Tag] (
  [TagId] int, (PK)
  [Name] nvarchar
  ...
)

[TagPost] (
  [TagId] int, (PK, FK)
  [PostId] int (PK, FK)
)

而且,TagId 和 PostId 是表上相应设置的 PK 和 FK 等。然后我在 c# 中有这些类和映射

public class Post {
    public Post()
    {
        this.Tags = new HashSet<Tag>();
    }

    [Key]
    public int PostId { get; set; }
    ...

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

public class Tag {
    public Tag()
    {
        this.Posts = new HashSet<Post>();
    }

    [Key]
    public int TagId { get; set; }
    ...

    public virtual ICollection<Post> Posts { get; private set; }
}

internal class MyDbContext : DbContext
{
    public DbSet<Post> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Post>().ToTable("Post");
        modelBuilder.Entity<Tag>().ToTable("Tag");

        modelBuilder.Entity<Post>()
            .HasMany(x => x.Tags)
            .WithMany(x => x.Posts)
        .Map(x =>
        {
            x.ToTable("TagPost");
            x.MapLeftKey("PostId");
            x.MapRightKey("TagId");
        });
    }

然后我有这段代码来查询它们

var list = (from p in ctx.Posts.Include(p => p.Tags)
            from t in p.Tags
            where ... // some of my filter conditions
            select p).ToList();

这个加入确实返回了我正在寻找的帖子,但是即使我在那里有包含,返回的帖子也没有填写它们的关联标签。有人可以帮助指出我缺少的内容,以便我可以让标签也随帖子一起返回吗?

非常感谢。

【问题讨论】:

    标签: linq entity-framework ef-code-first many-to-many


    【解决方案1】:

    双重from 是手动Join,它会导致Include 被忽略,如herehere 所述。对于其他 LINQ 方法 like grouping and projectionsInclude 也会被忽略。

    关系修正通常不适用于多对多关系,仅适用于在一端至少有一个引用的关系 - 一对多或一对一。如果您将Posts 和相关的Tags 投影到另一种类型(匿名或命名)中,则数据将正确加载,但由于关系是多对多 EF 不会自动在内存中创建关系,因此 @ 987654330@ 集合将保持为空。

    要使Include 正常工作,您必须从查询中删除第二个from,并将where 子句直接应用于Post 实体参数,例如:

    var list = (from p in ctx.Posts.Include(p => p.Tags)
                where p.Tags.Any(t => t.TagId == 1)
                select p).ToList();
    

    Tag 属性的过滤器在传递给.Any 的表达式中指定,.Any 是一个以Tag (t) 作为参数的表达式。

    【讨论】:

      【解决方案2】:

      尝试将所有内容选择到匿名对象中(类似这样)

      var list = (
              from p in ctx.Posts
              from t in p.Tags
              where ... // some of my filter conditions
              select new {
                  Posts = p,
                  Tags = p.Tags
              })
          .ToList();
      

      根据对我最初回答的反馈以及 EF 可以找到相关实体但无法填充 Tags 集合这一事实,我认为问题在于 Post 类中的 Tags 实体的定义。

      尝试从构造函数中删除 Hashset&lt;&gt; 初始化器并从集合声明中删除 private

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

      【讨论】:

      • 谢谢你!我看到您正在返回此匿名类型的列表,但是如何将每个具有 List 的帖子转换为 List
      • 修复应该自动填充每个Post 中的Tag 引用。
      • 我通过执行 list.Select(a=>a.Posts) 调试并查看了返回列表中的帖子,但其中没有填充标签。
      • 匿名类型的Tags属性填满了吗?
      • 是的,匿名类型中的Tags被填满了
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      相关资源
      最近更新 更多