实体框架多对多有效,但包含没有

时间:2013-03-21 19:10:48

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

我与这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();

此联接确实会返回我正在查找的帖子,但是即使我在那里包含了包含的内容,返回的帖子也不会填充相关标签。有人可以帮助指出我缺少的东西,以便我可以让标签也返回帖子吗?

非常感谢。

2 个答案:

答案 0 :(得分:3)

from是手动Join,会导致Include被忽略,如上所述herehere。其他LINQ方法like grouping and projections也会忽略Include

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

要使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的表达式中指定,该表达式以Tagt)作为参数。

答案 1 :(得分:0)

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

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<>初始化程序,并从集合声明中删除private

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