【问题标题】:EF Lambda include navigation propertiesEF Lambda 包含导航属性
【发布时间】:2020-05-23 20:22:00
【问题描述】:

我有以下对象,称为过滤器,具有以下属性:

    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Type> Types{ get; set; }
    public virtual ICollection<Step> Steps { get; set; }
    public virtual ICollection<Flow> Flows { get; set; }
    public virtual ICollection<Room> Rooms { get; set; }

当我从数据库中选择过滤器列表时,我不知道如何包含集合(类型、步骤、流程、房间)。我的代码如下:

var filters = (
            from filter in dbContext.DbSet<Filter>()
            let rooms = (
                from r in dbContext.DbSet<Room>()
                select r
                )
            let eventTypes = (
                from t in dbContext.DbSet<Type>()
                select t
                )
            let processFlows = (
                from f in dbContext.DbSet<Flow>()
                select f
                )
            let processFlowSteps = (
                from s in dbContext.DbSet<Step>()
                select s
                )
            select filter
            ).ToList();

我的Filter集合被返回了,但是里面的集合是空的。您能告诉我如何实现这一目标吗?

Ps:由于性能问题,我不想使用 Include,我不喜欢 Entity Framework 生成查询的方式,我想这样做。

【问题讨论】:

  • 为什么不用dbContext.Filters 而不是dbContext.DbSet&lt;Filter&gt;()
  • @juharr 这实际上是同一件事,所以没关系。
  • " 我不喜欢 Entity Framework 生成查询的方式,我想这样做" “这种方式”是什么意思?如果您的意思是显示的代码,显然它不起作用,因此绝对不能成为“方式”。即使您在select 中包含let 变量(例如select new { filter, rooms, etc.... }),生成的查询也会比Include 的查询差得多,因为let 查询将针对@987654330 的每条记录执行@ 桌子。结果集将是完整的笛卡尔积。对我来说听起来像是 XY 问题。
  • 只是一个一个地加载每个导航,我不知道你为什么需要让。您可以只实现过滤器,然后对每个集合执行相同操作,但这次您不需要存储结果。应该填充过滤器。
  • 通过延迟加载,您不需要被包含。

标签: c# entity-framework linq lambda


【解决方案1】:

你需要使用Include扩展方法:

var filters=dbContext.DbSet<Filter>()
                     .Include(f=>f.Types)
                     .Include(f=>f.Steps)
                     .Include(f=>f.Flows)
                     .Include(f=>f.Rooms)
                     .ToList()

更新

@MrSilent,Include 扩展方法正是为了加载相关实体而制作的,我认为您的另一个选择是执行 raw sql,但您正在做的方式不是您拥有的方式到您的数据库的四次往返,您需要使用 join 来获取相关实体,Include 为您生成这些联接,这只是一次往返。

这是,例如,我猜你可以这样做的另一种方式,但同样,它与使用 EF 的目的背道而驰,你的模型的想法也是表示你的表之间的关系,而不仅仅是单独表示它们

var query= from f in context.DbSet<Filter>()
           from s in f.Steps
           from r in f.Rooms
           from t in f.Types
           from fl in f.Flows
           select new {f, s, r, t, fl};

【讨论】:

  • 我投错票了,真的很抱歉。度过了令人筋疲力尽的一周。由于性能问题,我不想使用 Include,我不喜欢 Entity Framework 如何生成查询,我想这样做。
  • 这个答案完全符合问题的要求,“包括导航属性”。
【解决方案2】:

你的方法行得通,只是你做的有点不对。

要包含导航属性,您所要做的就是一个子选择(使用 linq),例如:

var filters = (from filter in dbContext.DbSet<Filter>()
                select new Filter
                {
                    filter.Id,
                    filter.Name,
                    Rooms = (from r in dbContext.DbSet<Room>()
                            where r.FilterId == filter.Id
                            select r).ToList()
                }).ToList();

请记住,在您调用返回方法(ToList、Any、FirstOrDefault 等)之前,EF 不会执行查询。有了这个,它不会执行那些你想通过不使用 Include() 来避免的丑陋查询,它会简单地触发两个查询并正确分配你想要的对象中的值。

【讨论】:

    【解决方案3】:

    你可以使用延迟加载,如何:

    您首先需要获取 Include 倾向于虚拟的属性,然后是受保护的访问类型的空构造函数才能做好工作。

    public virtual ICollection<Type> Types{ get; set; }
    public virtual ICollection<Step> Steps { get; set; }
    public virtual ICollection<Flow> Flows { get; set; }
    public virtual ICollection<Room> Rooms { get; set; }
    

    还有

     //FOR EF !
     protected Filter() { }
    

    我认为这个解决方案会解决你的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多