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

すべてのクエリ ロジックをリポジトリ内に保持しながら、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 オブジェクトを構築するときに、組織プロパティに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、すべてのロジックをリポジトリに保持できます。あなたのモデルについて間違った仮定をしている可能性は十分にありますが (サンプル コードは完全ではないため)、パターンの使用方法を理解するには十分だと思います。不明な点があればお知らせください。

于 2012-09-05T15:42:39.497 に答える
1

これは関連している可能性があります:

CTP4 Code First での CreateSourceQuery の使用

プロパティを asICollection<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 に答える
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 に答える