如何编写一个 where 查询以仅包含 1 个子实体

本文关键字:包含 实体 查询 where 何编写 一个 | 更新日期: 2023-09-27 18:36:17

我有实体

Blog{ blogId, name, creatorUserId }
BlogSettings{ blogId, userId, column1  }

现在我有一个接受blogIduserId的方法,我正在查询Blog(不是BlogSettings

Blog包含BlogSettings的集合。

我应该怎么做?

如果我写context.Blogs.Include("BlogSettings").Where( b => b.BlogId == blogId)那将非常低效,因为我只需要其用户ID == userId的博客设置。

Note: 我不是在博客设置上查询。如您所见,我正在查询博客集合。

如何编写一个 where 查询以仅包含 1 个子实体

var blogWithSetting = context.Blogs
    .Where(b => b.BlogId == blogId)
    .Select(b => new
    {
        Blog = b,
        BlogSetting = b.BlogSettings.FirstOrDefault(bs => bs.UserId == userId)
    })
    .SingleOrDefault();
if (blogWithSetting != null)
{
    Blog blog = blogWithSetting.Blog;
    //
}

此类投影是在单次往返数据库时获取结果的唯一方法,因为使用 Include 进行预先加载不支持对包含的子集合进行任何筛选或排序。如果不禁用更改跟踪并且关系不是多对多,blog.BlogSettings将自动填充单个加载的BlogSetting。否则,必须使用结果对象的属性手动填充集合:

if (blogWithSetting != null)
{
    Blog blog = blogWithSetting.Blog;
    blog.BlogSettings = new List<BlogSetting>();
    blog.BlogSettings.Add(blogWithSetting.BlogSetting);
    //
}

虽然名义上您是在Blog上查询,但您可能会发现针对BlogSettings编写查询并添加.Include("Blog")更有效。

Presumaby,对于UserId和BlogId的组合,你只有一个BlogSettings;也许这是由一个独特的约束强制执行的。 如果是这种情况,这将非常快:

    var blogAndSettings = (from s in context.BlogSettings
                                            .Include("Blog")
                           where s.BlogId = blogId && s.UserId = userId
                           select s).SingleOrDefault();

这将要求您创建从BlogSettingsBlog的名为 Blog 的导航属性。

这将执行Blog表和BlogSettings表之间的联接,但只是具体化BlogSetting实体。

var settings = context.Blogs.Where( b => b.BlogId == blogId && b.CreatorUserId = userId)
                            .SelectMany(x => x. BlogSettings);
context.Blogs.Include("BlogSettings").SingleOrDefault( b => b.BlogId == blogId);