EF使用延迟加载过滤子表

时间:2012-08-30 00:33:28

标签: entity-framework entity-framework-4

我正在使用带有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的产品。

这是可能的,如果是这样的话?

编辑我最好的猜测是可以将过滤器添加到实体的配置中。或者可能有一种方法来拦截/覆盖延迟加载调用并修改它。显然,如果我创建了一个组织存储库,我可以手动加载它,但我正在努力避免

5 个答案:

答案 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();