我有一个简单的问题,但似乎无法解决。我正在使用Entity Framework Core 2.0.1版,并且希望在默认情况下急于加载我的所有实体。
例:
public class Order { public int Id { get; set; } public string Name { get; set; } public int CustomerId { get; set; } public Customer Customer { get; set; } } public class Customer { public int Id { get; set; } public string Name { get; set; } public int AddressId { get; set; } public Address Address { get; set; } } public class Address { public int Id { get; set; } public string PostCode { get; set; } public string City { get; set; } }
但是,当我加载 Order 实体时,相关实体 Customer 然后在其内部 Address 为null
我试过的
这只是一个例子,我有多个嵌套级别的实体,并且我想在通用存储库中加载嵌套的相关数据,因此不能使用 Include 和 ThenInclude, 因为我不知道加载时的实际实体类型。
public virtual async Task<IEnumerable<T>> GetAllAsync(Expression<Func<T, bool>> predicate = null) { if (predicate == null) { return await Context.Set<T>().ToListAsync(); } return await Context.Set<T>().Where(predicate).ToListAsync(); }
我想念什么?我在存储库中有什么问题吗?任何对更好设计的帮助或指点(如果这就是这里的问题),将不胜感激。
谢谢
该功能目前正式不存在(EF Core 2.0.2以及即将推出的2.1)。已在“ 急切加载”中请求所有导航属性#4851(已关闭),目前已通过基于规则的急切加载(包括)#2953和允许在模型中声明聚合(例如,定义包含的属性或通过其他方式)进行跟踪#1985(均在积压中,即没有具体的时间表)。
我可以提供以下两种自定义扩展方法:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore.Metadata; namespace Microsoft.EntityFrameworkCore { public static partial class CustomExtensions { public static IQueryable<T> Include<T>(this IQueryable<T> source, IEnumerable<string> navigationPropertyPaths) where T : class { return navigationPropertyPaths.Aggregate(source, (query, path) => query.Include(path)); } public static IEnumerable<string> GetIncludePaths(this DbContext context, Type clrEntityType) { var entityType = context.Model.FindEntityType(clrEntityType); var includedNavigations = new HashSet<INavigation>(); var stack = new Stack<IEnumerator<INavigation>>(); while (true) { var entityNavigations = new List<INavigation>(); foreach (var navigation in entityType.GetNavigations()) { if (includedNavigations.Add(navigation)) entityNavigations.Add(navigation); } if (entityNavigations.Count == 0) { if (stack.Count > 0) yield return string.Join(".", stack.Reverse().Select(e => e.Current.Name)); } else { foreach (var navigation in entityNavigations) { var inverseNavigation = navigation.FindInverse(); if (inverseNavigation != null) includedNavigations.Add(inverseNavigation); } stack.Push(entityNavigations.GetEnumerator()); } while (stack.Count > 0 && !stack.Peek().MoveNext()) stack.Pop(); if (stack.Count == 0) break; entityType = stack.Peek().Current.GetTargetType(); } } } }
第一种只是应用多个字符串库的便捷方法Include。
Include
第二个步骤Include使用EF Core提供的元数据来完成收集类型的所有路径的实际工作。它基本上是从所传递的实体类型开始的有向循环图处理,不包括所包含路径的逆向导航,仅发送到“叶”节点的路径。
您的示例中的用法可能是这样的:
public virtual async Task<IEnumerable<T>> GetAllAsync(Expression<Func<T, bool>> predicate = null) { var query = Context.Set<T>() .Include(Context.GetIncludePaths(typeof(T)); if (predicate != null) query = query.Where(predicate); return await query.ToListAsync(); }