我正在使用带有POCO和存储库模式的实体框架,我想知道是否有任何方法来过滤子列表延迟加载。例如:
class Person
{
public virtual Organisation organisation {set; get;}
}
class Organisation
{
public virtual ICollection<Product> products {set; get;}
}
class Product
{
public bool active {set; get;}
}
目前我只有一个人员资料库,因为我总是从那时开始,所以理想情况下我想做以下事情:
Person person = personRepo.GetById(Id);
var products = person.organisation.products;
并且只从数据库中加载active = true的产品。
这是可能的,如果是这样的话?
编辑我最好的猜测是可以将过滤器添加到实体的配置中。或者可能有一种方法来拦截/覆盖延迟加载调用并修改它。显然,如果我创建了一个组织存储库,我可以手动加载它,但我正在努力避免
答案 0 :(得分:2)
通过延迟加载没有直接的方法来做到这一点,但是如果你愿意显式加载集合,你可以在this blog中关注什么,请参阅在显式加载相关实体时应用过滤器< / strong>部分。
context.Entry(person)
.Collection(p => p.organisation.products)
.Query()
.Where(u => u.IsActive)
.Load();
答案 1 :(得分:1)
这可能是相关的:
Using CreateSourceQuery in CTP4 Code First
如果您要将自己的属性重新定义为ICollection<T>
而不是IList<T>
并启用更改跟踪代理,那么您可以将它们转换为EntityCollection<T>
,然后调用{{1这将允许您对它们执行LINQ to Entities查询。
示例:
CreateSourceQuery()
答案 2 :(得分:1)
你可以做Mark Oreta和luksan建议的同时将所有查询逻辑保留在存储库中。
您所要做的就是将Lazy<ICollection<Product>>
传递给组织构造函数,并使用他们提供的逻辑。在访问惰性实例的value属性之前,它不会进行评估。
<强>更新强>
/*
First, here are your changes to the Organisation class:
Add a constructor dependency on the delegate to load the products to your
organization class. You will create this object in the repository method
and assign it to the Person.Organization property
*/
public class Organisation
{
private readonly Lazy<ICollection<Product>> lazyProducts;
public Organisation(Func<ICollection<Product>> loadProducts){
this.lazyProducts = new Lazy<ICollection<Product>>(loadProducts);
}
// The underlying lazy field will not invoke the load delegate until this property is accessed
public virtual ICollection<Product> Products { get { return this.lazyProducts.Value; } }
}
现在,在您的repository方法中,构造Person对象时,您将为Organization属性分配一个包含延迟加载字段的Organisation
对象。
因此,如果没有看到整个模型,它看起来就像
public Person GetById(int id){
var person = context.People.Single(p => p.Id == id);
/* Now, I'm not sure about the cardinality of the person-organization or organisation
product relationships, but let's assume you have some way to access the PK of the
organization record from the Person and that the Product has a reference to
its Organisation. I may be misinterpreting your model, but hopefully you
will get the idea
*/
var organisationId = /* insert the aforementioned magic here */
Func<ICollection<Product>> loadProducts = () => context.Products.Where(product => product.IsActive && product.OrganisationId == organisationId).ToList();
person.Organisation = new Organisation( loadProducts );
return person;
}
通过使用此方法,在访问Products
实例上的Organisation
属性之前,不会加载对产品的查询,并且可以将所有逻辑保留在存储库中。我很有可能对你的模型做出了错误的假设(因为示例代码非常不完整),但我认为这里有足够的内容供你查看如何使用模式。如果有任何不清楚的地方,请告诉我。
答案 3 :(得分:0)
您可以使用Query()方法来实现此目的。类似的东西:
context.Entry(person)
.Collection(p => p.organisation.products)
.Query()
.Where(pro=> pro.Active==true)
.Load();
请查看此页面click here
答案 4 :(得分:0)
您的存储库是否使用类似:
IQueryable<T> Find(System.Linq.Expressions.Expression<Func<T, bool>> expression)
如果是这样,你可以这样做:
var person = personRepo.Find(p => p.organisation.products.Any(e => e.active)).FirstOrDefault();