Linq to Entities 过滤器导航集合属性
Linq to Entities filter navigation collection properties
我有一个订单 class,它有两个集合类型的导航属性;订单详细信息和类别。 Order 与 OrderDetail 和 Category 之间存在一对多关系。订单可能有也可能没有与之关联的类别。 OrderDetail 记录有一个 CustomerID 字段。
我正在尝试检索具有关联类别的订单列表以及特定客户的相应 OrderDetail 记录。如果可能的话,我想使用 linq to entities 来实现这一点。
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;
你可以试试这个:
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}));
但我不喜欢这些solutions.The最直接的方式是你从一开始就有的查询。
Entity Framework 的默认设置是允许延迟加载和动态代理。
并且在这种情况下,当您在关系属性上使用 virtual 关键字时,这些 'should'(如果您没有在 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' statements),没有问题。但是如果你打算使用它,我会考虑使用下面的语法。如果您决定更改关系 属性.
的名称,这将导致编译错误
var load = data.Orders
.Include(x => x.OrderDetails)
.Include(x => x.Categories)
我建议您花 10-15 分钟的时间阅读这篇文章:
https://msdn.microsoft.com/en-us/data/jj574232.aspx
我有一个订单 class,它有两个集合类型的导航属性;订单详细信息和类别。 Order 与 OrderDetail 和 Category 之间存在一对多关系。订单可能有也可能没有与之关联的类别。 OrderDetail 记录有一个 CustomerID 字段。
我正在尝试检索具有关联类别的订单列表以及特定客户的相应 OrderDetail 记录。如果可能的话,我想使用 linq to entities 来实现这一点。
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;
你可以试试这个:
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}));
但我不喜欢这些solutions.The最直接的方式是你从一开始就有的查询。
Entity Framework 的默认设置是允许延迟加载和动态代理。
并且在这种情况下,当您在关系属性上使用 virtual 关键字时,这些 'should'(如果您没有在 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' statements),没有问题。但是如果你打算使用它,我会考虑使用下面的语法。如果您决定更改关系 属性.
的名称,这将导致编译错误var load = data.Orders
.Include(x => x.OrderDetails)
.Include(x => x.Categories)
我建议您花 10-15 分钟的时间阅读这篇文章: https://msdn.microsoft.com/en-us/data/jj574232.aspx