linq 实体框架链接查询Include()多个子实体

qoefvg9y  于 2023-01-18  发布在  其他
关注(0)|答案(6)|浏览(226)

这可能是一个真正的元素问题,但是当编写一个跨越三个级别(或更多)的查询时,什么是包含多个子实体的好方法呢?
例如,我有4张表:CompanyEmployeeEmployee_CarEmployee_Country
公司与员工之间的关系为1:m。
雇员与雇员_汽车和雇员_国家都具有1:m关系。
如果我想写一个查询,返回所有4个表的数据,我目前正在写:

Company company = context.Companies
                         .Include("Employee.Employee_Car")
                         .Include("Employee.Employee_Country")
                         .FirstOrDefault(c => c.Id == companyID);

必须有一个更优雅的方法!这是冗长的,并产生可怕的SQL
我在VS 2010中使用EF 4

6kkfgxo0

6kkfgxo01#

使用extension methods。将 NameOfContext 替换为对象上下文的名称。

public static class Extensions{
   public static IQueryable<Company> CompleteCompanies(this NameOfContext context){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country") ;
     }

     public static Company CompanyById(this NameOfContext context, int companyID){
         return context.Companies
             .Include("Employee.Employee_Car")
             .Include("Employee.Employee_Country")
             .FirstOrDefault(c => c.Id == companyID) ;
      }

}

然后你的代码变成

Company company = 
          context.CompleteCompanies().FirstOrDefault(c => c.Id == companyID);

     //or if you want even more
     Company company = 
          context.CompanyById(companyID);
wqsoz72f

wqsoz72f2#

EF核心

对于多于一个导航的急切加载关系(例如,孙子或祖父关系),其中中间关系是集合(即,具有原始“subject”的1对多),EF Core具有新的扩展方法.ThenInclude(),并且语法是旧EF 4-6语法的slightly different

using Microsoft.EntityFrameworkCore;
...

var company = context.Companies
                     .Include(co => co.Employees)
                           .ThenInclude(emp => emp.Employee_Car)
                     .Include(co => co.Employees)
                           .ThenInclude(emp => emp.Employee_Country)

加上一些注解

  • 如上所述(Employees.Employee_CarEmployees.Employee_Country),如果需要包含中间子集合的2个或更多子属性,则you'll need to repeat为集合的每个子集合提供.Include导航。
  • 就我个人而言,我会在.ThenInclude中保留额外的“缩进”,以保持您的理智。

对于与原始主题为1:1(或N:1)的中介体的串行化,也支持点语法,例如:

var company = context.Companies
                     .Include(co => co.City.Country);

这在功能上等同于:

var company = context.Companies
                     .Include(co => co.City)
                          .ThenInclude(ci => ci.Country);

但是,在EFCore中,使用“Select”通过与主题为1:N的中介链接的旧EF 4/ 6语法不受支持,即

var company = context.Companies
                     .Include(co => co.Employee.Select(emp => emp.Address));

通常会导致模糊错误,如
不支持“System.IntPtr”示例的序列化和反序列化

EF 4.1至EF 6

有一个strongly typed .Include,它允许通过提供Select表达式到适当的深度来指定所需的急切加载深度:

using System.Data.Entity; // NB!

var company = context.Companies
                     .Include(co => co.Employees.Select(emp => emp.Employee_Car))
                     .Include(co => co.Employees.Select(emp => emp.Employee_Country))
                     .FirstOrDefault(co => co.companyID == companyID);

生成的Sql一点也不直观,但看起来性能足够好。

cdmah0mi

cdmah0mi3#

您可能会对这篇文章感兴趣,它可以在codeplex.com上找到。

本文提出了一种新的方法,以声明性图形的形式表示跨多个表的查询。
此外,本文还将这种新方法与EF查询进行了全面的性能比较,分析表明GBQ的性能很快就优于EF查询。

im9ewurl

im9ewurl4#

How do you construct a LINQ to Entities query to load child objects directly, instead of calling a Reference property or Load()
没有其他方法--除了实现延迟加载。
或手动加载....

myobj = context.MyObjects.First();
myobj.ChildA.Load();
myobj.ChildB.Load();
...
llew8vvj

llew8vvj5#

可能会帮助一些人,4级和2个孩子的每一级

Library.Include(a => a.Library.Select(b => b.Library.Select(c => c.Library)))
            .Include(d=>d.Book.)
            .Include(g => g.Library.Select(h=>g.Book))
            .Include(j => j.Library.Select(k => k.Library.Select(l=>l.Book)))
tct7dpnv

tct7dpnv6#

为此:

namespace Application.Test
{
    using Utils.Extensions;
    public class Test
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Room> Rooms { get; set; }
        public DbSet<Post> Posts { get; set; }
        public DbSet<Comment> Comments { get; set; }
        
        public void Foo()
        {
            DB.Users.Include(x => x.Posts, x => x.Rooms, x => x.Members);
            //OR
            DB.Users.Include(x => x.Posts, x => x.Rooms, x => x.Members)
                .ThenInclude(x => x.Posts, y => y.Owner, y => y.Comments);
        }
    }
}

此扩展可能有帮助:

namespace Utils.Extensions
{
    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    public static partial class LinqExtension
    {
        public static IQueryable<TEntity> Include<TEntity>(
            this IQueryable<TEntity> sources,
            params Expression<Func<TEntity, object>>[] properties)
            where TEntity : class
        {
            System.Text.RegularExpressions.Regex regex = new(@"^\w+[.]");
            IQueryable<TEntity> _sources = sources;
            foreach (var property in properties)
                _sources = _sources.Include($"{regex.Replace(property.Body.ToString(), "")}");
            return _sources;
        }

        public static IQueryable<TEntity> ThenInclude<TEntity, TProperty>(
            this IQueryable<TEntity> sources,
            Expression<Func<TEntity, IEnumerable<TProperty>>> predicate,
            params Expression<Func<TProperty, object>>[] properties)
            where TEntity : class
        {
            System.Text.RegularExpressions.Regex regex = new(@"^\w+[.]");
            IQueryable<TEntity> _sources = sources;
            foreach (var property in properties)
                _sources = _sources.Include($"{regex.Replace(predicate.Body.ToString(), "")}.{regex.Replace(property.Body.ToString(), "")}");
            return _sources;
        }
    }
}

相关问题