EntityFramework:急切加载而不是包含?

我的数据模型有很多嵌套实体 ,我想热切地加载整个对象树…除了将按需显式加载的视图实体。

使用包含路径我必须指定许多路径,每次添加新实体时,我都必须调整这些包含路径。 我目前使用我的存储库的以下方法来加载类型的所有实体:

public virtual IQueryable All(string commaSeperatedIncludePropertyPaths = "") { IQueryable initialQuery = Context.Set(); string[] includePaths = commaSeperatedIncludePropertyPaths.Split(new[] { ','}, StringSplitOptions.RemoveEmptyEntries); return includePaths.Aggregate(initialQuery, (currentQuery, includeProperty) => currentQuery.Include(includeProperty)); } 

传递的包含路径已经填满整个屏幕。

因此,我希望EntityFramework能够自动加载所有导航属性 ,除了我使用排除路径指定的属性

 public virtual IQueryable All(string commaSeperatedExcludePropertyPaths = "") { //... how to implement? } 

排除路径有助于避免循环依赖,并过滤掉我不想急切加载的少数实体。 指定排除而不是包含会减少样板代码。

这可能是EF 6.1.3还是EF 7的计划? 如果没有,那么选择的原因是什么?

有没有人已经尝试读取实体元数据并将其应用于“自动急切加载”并失败了?

相关(旧)问题和文章:

  • 加载导航属性的选项概述:

https://msdn.microsoft.com/en-us/magazine/hh205756.aspx

  • 自动急切加载

entity framework自动加载

entity framework – 有没有办法在没有Include()的情况下自动加载子实体?

entity frameworklinq查询Include()多个子实体

  • 类型保存包括

entity framework.Include()与编译时检查?

以下是解决方案的初稿。 我仍然需要弄清楚它是否切实可行……我也会考虑重新加载加载方法(正如Lanorkin建议的那样)。 谢谢您的意见。

编辑

事实certificate,虽然排除在开发应用程序时可能有意义……对域模型进行了许多更改……但排除并不比我刚才考虑的“真实世界示例”包含更优雅。

a)我浏览了我的实体并计算了包含和排除的导航属性的数量。 排除属性的平均数量并不比包含的属性数量小得多。

b)如果我确实考虑了排除的不同导航属性“foos”,我将被迫考虑Foo类型的子实体的排除…如果我根本不想使用它的属性。

另一方面,使用包含,我只需要指定导航属性“foos”,而不需要为子实体指定任何其他内容。

因此,虽然排除可能会保留一个级别的某些规格,但它们需要更多规格才能进入下一级…(当排除某些中间实体而不仅仅是位于加载的对象树的叶子上的实体时)。

c)此外,包含/排除可能不仅取决于实体的类型,还取决于用于访问实体的路径。 然后需要指定排除,例如“在为一个目的加载实体时排除属性xy,并在为另一目的加载实体时排除属性z”。

=> 由于这些考虑,我将继续使用包含

我实现了基于包含字典而不是字符串的类型保存包含:

  private static readonly Inclusions _personInclusionsWithCompanyParent = new Inclusions(typeof(Company)) { {e => e.Company, false}, {e => e.Roles, true} }; 

我有一个方法,从包含列表创建查询。 该方法还检查字典中是否考虑了所有现有导航属性。 如果我添加一个新实体并忘记指定相应的包含,则会抛出exception。


不过,这里有一个使用排除的实验解决方案而不是包括:

 private const int MAX_EXPANSION_DEPTH = 10; private DbContext Context { get; set; } //set during construction of my repository public virtual IQueryable AllExcluding(string excludeProperties = "") { var propertiesToExclude = excludeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); IQueryable initialQuery = Context.Set(); var elementType = initialQuery.ElementType; var navigationPropertyPaths = new HashSet(); var navigationPropertyNames = GetNavigationPropertyNames(elementType); foreach (var propertyName in navigationPropertyNames) { if (!propertiesToExclude.Contains(propertyName)) { ExtendNavigationPropertyPaths(navigationPropertyPaths, elementType, propertyName, propertyName, propertiesToExclude, 0); } } return navigationPropertyPaths.Aggregate(initialQuery, (current, includeProperty) => current.Include(includeProperty)); } private void ExtendNavigationPropertyPaths(ISet navigationPropertyPaths, Type parentType, string propertyName, string propertyPath, ICollection propertiesToExclude, int expansionDepth) { if (expansionDepth > MAX_EXPANSION_DEPTH) { return; } var propertyInfo = parentType.GetProperty(propertyName); var propertyType = propertyInfo.PropertyType; var isEnumerable = typeof(IEnumerable).IsAssignableFrom(propertyType); if (isEnumerable) { propertyType = propertyType.GenericTypeArguments[0]; } var subNavigationPropertyNames = GetNavigationPropertyNames(propertyType); var noSubNavigationPropertiesExist = !subNavigationPropertyNames.Any(); if (noSubNavigationPropertiesExist) { navigationPropertyPaths.Add(propertyPath); return; } foreach (var subPropertyName in subNavigationPropertyNames) { if (propertiesToExclude.Contains(subPropertyName)) { navigationPropertyPaths.Add(propertyPath); continue; } var subPropertyPath = propertyPath + '.' + subPropertyName; ExtendNavigationPropertyPaths(navigationPropertyPaths, propertyType, subPropertyName, subPropertyPath, propertiesToExclude, expansionDepth + 1); } } private ICollection GetNavigationPropertyNames(Type elementType) { var objectContext = ((IObjectContextAdapter)Context).ObjectContext; var entityContainer = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace); var entitySet = entityContainer.EntitySets.FirstOrDefault(item => item.ElementType.Name.Equals(elementType.Name)); if (entitySet == null) { return new List(); } var entityType = entitySet.ElementType; return entityType.NavigationProperties.Select(np => np.Name) .ToList(); }