【问题标题】:EF4 - Easy way to load all related entities?EF4 - 加载所有相关实体的简单方法?
【发布时间】:2011-12-02 21:29:47
【问题描述】:

在 EF4 中是否有一种相对简单的方法可以快速加载实体的所有相关实体?我认为扩展方法将是完美的。我有一个场景,我正在使用 POCO,其中一个实体具有其他实体的多个导航属性,而这些实体又具有自己的导航属性。不用说,急切地加载所有内容需要大量的循环和加载。我希望在调用扩展方法时加载并准备好所有属性,以便关闭 LazyLoading。

类似:

using(var context = new MyEntities())
{
   var widget = context.Widgets.FirstOrDefault();
   widget.RecursivelyLoadAllPropertiesForMe() // magical extension method I wished existed
}

【问题讨论】:

  • 为什么要“大量循环”?实际上,您只需要很多 Include 运算符,可能带有像 Include("Customer.Contacts") 这样的虚线路径。为此,每个实体都有一个扩展方法不是问题。但我不确定:您是否正在寻找一种方法来加载所有实体类型的导航属性而不明确指定所有这些Includes?
  • 您必须在获取小部件之前定义包含。如果您尝试仅通过迭代和移动所有导航属性来加载所有内容,性能将非常糟糕。
  • @Slauma 没错,我不想手动指定所有的包含。
  • 您确实意识到使用 LazyLoading 会为您完成这一切! (而且效率很高,因为它只会在您实际要求相关项目时才麻烦)?

标签: entity-framework poco


【解决方案1】:

渴望加载始终是明确的 - 没有自动化。您必须为要加载的所有关系定义包含。如果您不这样做,您几乎总是会以对每个关系使用新查询的解决方案结束。

您的扩展方法必须使用:

((EntityCollection<...>)entity.NavigationCollection).Load();

如果需要加载子关系也可以调用:

((EntityCollection<...>)entity.NavigationCollection).CreateSourceQuery()
                                                    .Include(...)
                                                    .Execute();

但每次调用LoadExecute 仍会创建一个新的数据库查询,您必须编写代码来执行这些调用。此外,您必须拥有代理实体才能将常见的 ICollection&lt;...&gt; 转换为 EntityCollection&lt;...&gt;,并且您必须使用常见的预加载加载所有简单的导航属性(不是集合)。

【讨论】:

    【解决方案2】:

    这是我想出的扩展方法:

    public static void LoadAllProperties<T>(this T entity, ObjectContext context)
    {
        Type type = entity.GetType();
        context.Refresh(RefreshMode.ClientWins, entity);
        foreach (var property in type.GetProperties())
        {
            if (property.PropertyType.Name.StartsWith("ICollection"))
            {
                context.LoadProperty(entity, property.Name);
                var itemCollection = property.GetValue(entity, null) as IEnumerable;
                foreach (object item in itemCollection)
                {
                    item.LoadAllProperties(context);
                }
            }
        }
    }
    

    此方法首先通过从上下文中刷新实体来加载正常的实体属性值。然后,它遍历每个属性以查找作为集合的导航属性,并将递归加载集合中的每个项目。这对于我需要的东西非常有效,并且不需要您使用代理或包含。

    用法:

    using(var context = new MyEntities())
    {
        context.ContextOptions.ProxyCreationEnabled = false;
        var widget = context.Widgets.FirstOrDefault();  
        widget.LoadAllProperties(context);
    }
    

    【讨论】:

    • @LadislavMrnka 我同意,我只会在您知道您没有加载大量对象时使用它。
    【解决方案3】:

    是的,有!走吧:

    widget.Load()
    

    或者如果你去了:

    var widget = context.Widgets.FirstOrDefault().Include("SomeRelatedEntities").Include("OtherRelatedEntities");
    

    你不需要!

    【讨论】:

      【解决方案4】:

      第 1 步
      context.DataContext.ContextOptions.ProxyCreationEnabled = true; context.DataContext.ContextOptions.LazyLoadingEnabled = true;

      第 2 步 将虚拟关键字添加到导航器属性

        public class BankBranche 
         {
          public int Id { get; set; }
      
          public string Name { get; set; }
      
          public string Code { get; set; }
      
          public int BankId { get; set; }
      
          public virtual Address Address { get; set; }
      
          public virtual Bank Bank { get; set; }
      

      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多