【问题标题】:Load Collection Items In EF Core (OwnsMany)在 EF Core (OwnsMany) 中加载收集项
【发布时间】:2020-08-16 05:39:38
【问题描述】:

如何查询和过滤由OwnsMany函数为其所有者配置的集合属性中的数据?

这是我尝试过的示例:

using (var context = new BloggingContext())
{
    context.Database.OpenConnection();
    context.Database.EnsureCreated();

    context.Blogs.Add(sampleBlog);
    context.SaveChanges();

    var blog = context.Blogs.Single(b => b.BlogId == 1);

    var goodPosts = context.Entry(blog)
        .Collection(b => b.Posts)
        .Query()
        .Where(p => p.Title == "...")
        .ToList();
}

和模型类:

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

}
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

和 dbContext 类:

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().OwnsMany(x => x.Posts, post =>
        {
            post.ToTable("Posts");
            post.HasKey("Id");

            post.Property(x => x.Title);
            post.Property(x => x.Content);
        });
        modelBuilder.Entity<Blog>()
            .ToTable("Blogs");
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        var connection = new SqliteConnection("Data Source=:memory:");
        optionsBuilder.UseSqlite(connection);
    }
}

我遇到了这个异常:

System.Reflection.TargetInvocationException: '调用的目标抛出了异常。'

内部异常:

ArgumentException:“System.Collections.Generic.List`1[Post]”类型的表达式不能用于返回类型“Post”

【问题讨论】:

    标签: c# entity-framework orm entity-framework-core


    【解决方案1】:

    不幸的是,您遇到了 EF Core 错误/缺陷/问题,更具体地说,是在他们为拥有的实体类型集合的 Query() 方法实现中。

    目前最新的官方 EF Core 3.1.7 版本和 EF Core 5 预览版都可以重现,因此值得向他们的GitHub Issue Tracker 报告。 Query()之后的代码无关紧要,问题是用just复制的

    context.Entry(blog).Collection(b => b.Posts).Query();
    

    现在解决方法。有问题的方法主要用于显式加载。但是对拥有的实体类型的导航总是急切地加载,这可能就是为什么他们在添加拥有的实体类型的集合功能时错过了这种情况(它适用于常规的一对多导航和常规/拥有的参考导航)。不管是什么原因,在他们修复它之前,您不应该使用Query() 方法,而是使用 LINQ 手动编写查询。例如,使用示例Query 方法的以下等效项:

    context.Blogs.Where(b => b.BlogId == blog.BlogId).SelectMany(b => b.Posts)
    

    但现在它强加了另一个错误/要求:

    跟踪查询项目拥有的实体,结果中没有相应的所有者。如果没有所有者,则无法跟踪拥有的实体。要么在结果中包含所有者实体,要么使用 AsNoTracking() 使查询不跟踪。

    因此,您还需要将AsNoTracking() 添加到您的goodPosts 查询中。

    或者,在这种特殊情况下,由于拥有的实体集合已经与所有者一起加载/跟踪,因此使用 LINQ to Objects 来查询内存中的物化集合,这是通过将 Query() 替换为 CurrentValue 来实现的:

    var goodPosts = context.Entry(blog)
        .Collection(b => b.Posts)
        .CurrentValue
        .Where(p => p.Title == "...")
        .ToList();
    

    或直接使用导航属性:

    var goodPosts = blog.Posts
        .Where(p => p.Title == "...")
        .ToList();
    

    【讨论】:

      【解决方案2】:

      @Ivan-Stoev 的回答很好。

      关于 AsNoTracking():

      如果您想更新父实体和/或其子实体,请使用此

      var blog = context.Blogs.FirstOrDefault(b => b.BlogId == 1);
      //Manipulating the blog here.
      context.SaveChange();
      

      但如果您只需要读取博客的数据而不需要更新,请使用此

      var blog = context.Blogs.AsNoTracking().FirstOrDefault(b => b.BlogId == 1);
      //What ever code you have here.
      

      Breaking changes included in EF Core 3.0 是您可以查看的另一篇不错的文章。

      编码愉快,干杯!

      【讨论】:

        猜你喜欢
        • 2021-11-29
        • 1970-01-01
        • 2018-11-06
        • 2021-03-11
        • 2019-03-26
        • 2019-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多