[英]Entity Framework - Selective Condition on Included Navigation Property
Assume I have these simplified EF generated entities... 假设我有这些简化的EF生成实体......
public class PurchaseOrder
{
public int POID {get;set;}
public int OrderID {get;set;}
public int VendorID {get;set;}
public IEnumerable<Order> Orders {get;set;}
}
public class Order
{
public int OrderID {get;set;}
public decimal Price {get;set;}
public IEnumerable<Item> Items {get;set;}
}
public class Item
{
public int OrderID {get; set;}
public string SKU {get;set;}
public int VendorID {get;set;}
public Order Order {get;set;}
}
Business Logic: 商业逻辑:
An order can have multiple POs, one for each distinct vendor on the order (vendors are determined at the Item level). 订单可以有多个PO,一个用于订单上的每个不同供应商(供应商在物料级别确定)。
How Can I selectively Include Child Entities? 我如何选择性地包括儿童实体?
When querying for POs, I want to automatically include child entites for Order and Item. 查询PO时,我想自动为订单和项目添加子项目。
I accomplish this, using Include()... 我完成了这个,使用Include()...
Context.PurchaseOrders.Include("Orders.Items");
This does it's job and pulls back related entities, but, I only want to include Item entities whose VendorID matches the VendorID of the PurchaseOrder entity . 这是它的工作并拉回相关实体,但是, 我只想包含其VendorID与PurchaseOrder实体的VendorID匹配的Item实体 。
With traditional SQL, I'd just include that in the JOIN condition, but EF builds those internally. 对于传统的SQL,我只是在JOIN条件中包含它,但EF在内部构建它们。
What LINQ magic can I use tell EF to apply the condition, without manually creating the JOINs between the entities? 我可以使用什么LINQ魔术告诉EF应用条件,而无需在实体之间手动创建JOIN?
You can't selectively pull back certain child entities that match a certain condition. 您无法有选择地撤回符合特定条件的某些子实体。 The best you can do is manually filter out the relevant orders yourself.
您可以做的最好的事情是自己手动过滤相关订单。
public class PurchaseOrder
{
public int POID {get;set;}
public int OrderID {get;set;}
public int VendorID {get;set;}
public IEnumerable<Order> Orders {get;set;}
public IEnumerable<Order> MatchingOrders {
get {
return this.Orders.Where(o => o.VendorId == this.VendorId);
}
}
}
You can't. 你不能。 EF doesn't allow conditions for eager loading.
EF不允许急切加载的条件。 You must either use multiple queries like:
您必须使用多个查询,例如:
var pos = from p in context.PurchaseOrders.Include("Order")
where ...
select p;
var items = from i in context.Items
join o in context.Orders on new { i.OrderId, i.VendorId}
equals new { o.OrderId, o.PurchaseOrder.VendorId }
where // same condition for PurchaseOrders
select i;
Or you can use projection in single query: 或者您可以在单个查询中使用投影:
var data = from o in context.Orders
where ...
select new
{
Order = o,
PurchaseOrder = o.PurchaseOrder,
Items = o.Items.Where(i => i.VendorId == o.PurchaseOrder.VendorId)
};
You could use the IQueryable-Extensions here: 您可以在此处使用IQueryable-Extensions:
https://github.com/thiscode/DynamicSelectExtensions https://github.com/thiscode/DynamicSelectExtensions
The Extension builds dynamically an anonymous type. Extension以动态方式构建匿名类型。 This will be used for projection as described by @Ladislav-Mrnka.
这将用于@ Ladislav-Mrnka描述的投影。
Then you can do this: 然后你可以这样做:
var query = query.SelectIncluding( new List<Expression<Func<T,object>>>>(){
//Example how to retrieve only the newest history entry
x => x.HistoryEntries.OrderByDescending(x => x.Timestamp).Take(1),
//Example how to order related entities
x => x.OtherEntities.OrderBy(y => y.Something).ThenBy(y => y.SomeOtherThing),
//Example how to retrieve entities one level deeper
x => x.CollectionWithRelations.Select(x => x.EntityCollectionOnSecondLevel),
//Of course you can order or subquery the deeper level
//Here you should use SelectMany, to flatten the query
x => x.CollectionWithRelations.SelectMany(x => x.EntityCollectionOnSecondLevel.OrderBy(y => y.Something).ThenBy(y => y.SomeOtherThing)),
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.