我有一个order类,它有两个集合类型的导航属性;OrderDetails和Categories。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;
你可以试试:
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
。一种选择是在使用result:
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}));
但是这些解决方案我都不喜欢。最直接的方法是您从一开始就已经有的查询。
实体框架的默认设置是允许延迟加载和动态代理。
在这种情况下,当你在关系属性上使用虚拟关键字时,这些"应该"(如果你没有在EF中禁用它)会用延迟加载加载。
Lazy Loading在需要的时候加载关系属性。例子:
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()
你所描述的情况是急切加载('Include'语句),没有问题。但是如果你打算使用它,我会考虑使用下面的语法代替。如果您决定更改关系属性的名称,这将导致编译错误。
var load = data.Orders
.Include(x => x.OrderDetails)
.Include(x => x.Categories)
我建议你花10-15分钟的时间阅读这篇文章:https://msdn.microsoft.com/en-us/data/jj574232.aspx