【问题标题】:Entity Framework 6.1.3: Projection - load children of children directlyEntity Framework 6.1.3:Projection - 直接加载children的children
【发布时间】:2016-04-18 11:41:36
【问题描述】:

我的目标是只访问一次数据库,并通过过滤的子集合获取订单。

为了实现这一点,我使用了投影:

using (var db = new context())
            {
                var query = from o in db.Orders
                           select
                               new
                               {
                                   Order = o,
                                   Events = o.Events.Where(
                                       e => e.SomeBool 
                                       && e.SomeBool2
                                   ),

                                   EventsGroups = o.Events.Where(
                                       e => e.SomeBool 
                                       && e.SomeBool2
                                   ).Select(e => e.Groups),

                               };
            }

这里的问题是子集合“组”事件没有加载。为了解决这个问题,我在查询中将它作为另一个属性“EventsGroups”加载,然后我可以将其与事件放在一起。

我的问题:有没有办法将孩子“组”直接加载到“事件”上,这样我就不必将它们作为另一个属性获取?

沿线

Events = o.Events.Where(
e => e.SomeBool 
&& e.SomeBool2
).Include(e => e.Groups), //this cannot be done this way

为什么我使用投影而不是预先加载:

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

Filtering include items in LINQ and Entity Framework

底层类:

public class Order
{
    public Order()
    {
        Events = new HashSet<Event>();
    }

    public int Id { get; set; }

    public virtual ICollection<Event> Events { get; set; }
}

public class Event
{
    public Event()
    {
        Groups = new HashSet<Group>();
    }

    public int Id { get; set; }

    public bool SomeBool { get; set; }

    public bool SomeBool2 { get; set; }

    public virtual ICollection<Group> Groups { get; set; }
}

public class Group
{
    public Group()
    {
        Events = new HashSet<Event>();
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Event> Events { get; set; }
}

【问题讨论】:

  • 你可以试试o.Events.include(e =&gt; e.Groups).Where(... 吗?
  • 你的意思是在投影里面?我不相信 Include 存在那里imgur.com/ZOOXx0E
  • 对不起,我认为@Ivans 下面的回答应该可以工作

标签: c# entity-framework linq projection anonymous-types


【解决方案1】:

由于Include不能与匿名投影结合,您需要像投影Order.Events一样投影Event.Groups,即使用另一种匿名类型投影:

var query = from o in db.Orders
            select new
            {
                Order = o,
                Events = (from e in o.Events
                          where e.SomeBool && e.SomeBool2
                          select new
                          {
                              Event = e,
                              Groups = e.Groups,
                          }),
            };

【讨论】:

  • 这比我的做法漂亮多了,而且更容易组合。我怀疑这是一个结束,因为我可以避免循环来从任意对象构造 DTO 对象。
  • 如果你有 DTO 对象,你可以直接投影到它们而不是匿名类型 - EF 支持。
【解决方案2】:

您可以通过设置 Configuration.LazyLoadingEnabled = true; 来加载所有内容,而不需要任何 Include ,当然...性能必须牢记..取决于..

    public MyDatabaseContext(string databaseName)
        : base(databaseName)
    {
        Configuration.LazyLoadingEnabled = true;
    }

【讨论】:

  • 这违背了我只访问数据库一次的目标
【解决方案3】:

我相信这应该适合你:

using (var db = new context())
{
  var query = db.Orders
    .Include(o=>o.Events)
    .Include(o=>o.Events.Select(e=>e.Groups))
    .Select(o=>new
    {
      Order = o,
      Events = o.Events.Where(e => e.SomeBool && e.SomeBool2)
    });
}

如果没有,这将:

using (var db = new context())
{
  var query = db.Orders
    .Include(o=>o.Events)
    .Include(o=>o.Events.Select(e=>e.Groups))
    .Select(o=>new Order
    {
      Id=o.Id,
      Events = o.Events.Where(e => e.SomeBool && e.SomeBool2).ToList()
    });
}

【讨论】:

  • 这在测试时不起作用。组未加载。获取订单和过滤事件有效,但事件组只有一个空列表。包含似乎没有做任何事情,因为无论有没有它们,结果都是一样的。
  • 嗯。有趣的。一个简单的解决方法是在 Include 和 Select 之间添加 .ToList()。这肯定会奏效,但是,您将检索所有事件记录,而不仅仅是符合您的 .Where 条件的记录。
猜你喜欢
  • 1970-01-01
  • 2017-12-18
  • 1970-01-01
  • 1970-01-01
  • 2023-01-11
  • 1970-01-01
  • 2019-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多