简体   繁体   中英

EF eagerly load filtered child objects / filter only childs

my EF Poco classes structure as below and what I try to achieve is to get all CategoryProducts Including Products and ProductName but only ProductNames having languageid=1

I dont want to filter Root objects. I need not all productnames are loaded but only productname with languageid=1

I dont know how to achieve this. for example, I tried query below

var products =  db.CategoryProduct.Include("Product.ProductName").
Where(p=>p.Product.ProductName.Any(a=>a.LanguageId==1)).ToList();

But this one filters all categoryProducts which have ProductName with languageid=1. this is not what I want because all products have names in 5 different languages. I just dont want to load eagerly for each product 5 times but only 1 time for languageid=1

public partial class CategoryProduct
{
    [Key]    
  public int ProductId { get; set; }
 public virtual Product Product { get; set; }

}

public partial class Product
{

        public virtual ICollection<ProductName> ProductName { get; set; }

}

public partial class ProductName
{
     public int ProductId { get; set; }
     public int LanguageId { get; set; }
     public string Name { get; set; }

    public virtual Product Product { get; set; }
}

this is not easily doable, but something like the following may do it:

from cp in db.CategoryProduct.Include(x => x.Product)
from pn in cp.Product.ProductName.Where(x => x.LanguageId == 1).DefaultIfEmpty()
select new {
    Cat = cp,
    Name1 = pn.Name
}

then you have you product in Cat.Product, and the name in Name1.

The basic idea is to set a LEFT JOIN on ProductName .

I'm afraid that using eager loading you can't filter the related entities unless you project your query in an anonymous type or a DTO :

var products = db.CategoryProduct.Include(c=>c.Product.ProductName)
                                 .Select(c=> new CategoryProductDTO()
                                             {
                                               //...
                                               ProductNames= c.Product.ProductName.Where(a=>a.LanguageId==1)
                                             })
                                 .ToList();

If you don't want to project your query and you want to load specific related entities, then I suggest you to use Explicit Loading:

var catproduct =  db.CategoryProduct.Include(c=>c.Product).FirstOrDefault();// This is just an example, select the category product that you need to load the related entities
context.Entry(catproduct.Product) 
        .Collection(b => b.ProductName) 
        .Query() 
        .Where(pn => pn.LanguageId==1) 
        .Load(); 

But IMHO the first variant is the way to go

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM