Linq to Entities过滤导航集合属性

时间:2015-06-08 23:11:42

标签: c# linq entity-framework linq-to-entities

我有一个订单类,它有两个类型集合的导航属性;订单详细信息和类别。 Order与OrderDetail和Category之间存在一对多的关系。订单可能有也可能没有与之关联的类别。 OrderDetail记录具有CustomerID字段。

我正在尝试检索具有与之关联的类别的订单列表以及特定客户的相应OrderDetail记录。如果可能的话,我想使用linq实现这一点。

public class order
{
    public order()
    {
        OrderDetails = new list<OrderDetail>();
        Categories = new list<Category>();
    }
    public int OrderID { get; set; }
    public DateTime OrderDate { get; set; }
    public virtual List<OrderDetail> OrderDetails { get; set; }
    public virtual List<Category> Categories{ get; set; }
}

public class OrderDetail
{
    public int OrderDetailID { get; set; }
    public int CustomerID { get; set; }
    public virtual Order Order { get; set; }
}

public class Category
{
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public virtual Order Order { get; set; }
}

如果我首先使用OrderDetail实体开始,我可以使用它,如下所示,但如果我想先从Order实体开始,我该怎么写呢?

var query = from od in _dbCtx.OrderDetails
                .Include("Order")
                .Include("Order.Categories")
                where od.CustomerID == custID && od.Order.Categories.Count > 0
                select od;

2 个答案:

答案 0 :(得分:2)

你可以试试这个:

var query =_dbCtx.Orders.Include("OrderDetails")
                        .Include("Categories")
                        .Where(o=>o.Categories.Count>0)
                        .SelectMany(o=>o.OrderDetails.Where(od=>od.CustomerID == custID));

此查询中的关键是SelectMany扩展方法,用于将Where的结果展平为一个集合。

编辑1

由于您已禁用延迟加载,因此执行查询时获得的OrderDetails中的Order导航属性为null。使用结果时,一种选择可能是使用Load方法:

foreach(var od in query)
{
   // Load the order related to a given OrderDetail
   context.Entry(od).Reference(p => p.Order).Load();

   // Load the Categories related to the order
   context.Entry(blog).Collection(p => p.Order.Categories).Load();
}

另一种选择可能是返回匿名类型:

var query =_dbCtx.Orders.Include("OrderDetails")
                        .Include("Categories")
                        .Where(o=>o.Categories.Count>0)
                        .SelectMany(o=>o.OrderDetails.Where(od=>od.CustomerID == custID).Select(od=>new {Order=o,OrderDetail=od}));

但我不喜欢这些解决方案中的任何一个。最直接的方法是从一开始就有的查询。

答案 1 :(得分:0)

Entity Framework的默认设置是允许延迟加载和动态代理。

在这种情况下,当您在关系属性上使用虚拟关键字时,这些'应该'(如果您没有在EF中禁用它)加载延迟加载。

延迟加载在需要时加载关系属性。例如:

var load = data.Orders.OrderDetails.Tolist() // Would load all OrderDetails to a list.

//Below would load all OrderDetails that has a OrderId smaller than 5
var loadSpecific = data.Orders.Where(x=> x.OrderId < 5).OrderDetails.ToList() 

您描述的案例是Eager Loading('Include'语句),没有错。但是如果您打算使用它,我会考虑使用以下语法。如果您决定更改关系属性的名称,则会出现编译错误。

var load = data.Orders
.Include(x => x.OrderDetails)
.Include(x => x.Categories)

我建议您花10到15分钟的时间阅读本文: https://msdn.microsoft.com/en-us/data/jj574232.aspx