3

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

这可能吗?如果可以,怎么办?

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

4

5 回答 5

2

通过延迟加载没有直接的方法,但如果您愿意显式加载集合,您可以按照此博客中的内容进行操作,请参阅显式加载相关实体时应用过滤器部分。

context.Entry(person)
    .Collection(p => p.organisation.products)
    .Query()
    .Where(u => u.IsActive)
    .Load();
于 2012-08-30T01:21:20.267 回答
1

这可能是相关的:

首先在 CTP4 代码中使用 CreateSourceQuery

如果您将属性重新定义为ICollection<T>而不是IList<T>启用更改跟踪代理,那么您可能能够将它们转换为EntityCollection<T>然后调用CreateSourceQuery()这将允许您对它们执行 LINQ to Entities 查询。

例子:

var productsCollection = (EntityCollection<Product>)person.organisation.products;
var productsQuery = productsCollection.CreateSourceQuery();
var activeProducts = products.Where(p => p.Active);
于 2012-08-30T01:23:41.543 回答
1

您可以执行 Mark Oreta 和 luksan 的建议,同时将所有查询逻辑保留在存储库中。

您所要做的就是将 a 传递给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; } }
}

现在,在您的存储库方法中,当您构造 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;
 }

By using this approach, the query for the products will not be loaded until you access the Products property on the Organisationinstance, and you can keep all your logic in the repository. There's a good chance that I made incorrect assumptions about your model (as the sample code is quite incomplete), but I think there is enough here for you to see how to use the pattern. Let me know if any of this is unclear.

于 2012-09-05T15:42:39.497 回答
0

您可以使用 Query() 方法来实现这一点。就像是:

 context.Entry(person)
            .Collection(p => p.organisation.products)
            .Query()
            .Where(pro=> pro.Active==true)
            .Load();

看看这个页面点击这里

于 2012-08-30T01:03:39.113 回答
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();
于 2012-08-30T01:11:48.077 回答