![](/img/trans.png)
[英]Breeze **expand** vs. EntityFramework **include** for eager loading of navigation properties
[英]EntityFramework Core: Eager loading navigation properties of derived types
我正在使用EntityFramework Core,並試圖急切加載僅存在於某些派生類型(全部都在單個查詢中)的導航屬性。 最好用一個簡單的例子來演示。
假設您有一些數據結構,例如
class Transaction
{
public Product product { get; set; }
public DateTime date { get; set; }
}
abstract class Product
{
public string Name { get; set; }
}
class PhysicalProduct : Product
{
public Photo photo { get; set; }
}
class Service : Product
{
public Person provider { get; set; }
}
還有一些DbContext
class MyContext : DbContext
{
public DbSet<Transaction> Transactions;
}
如何查詢MyContext.Transactions以返回所有事務,並包括(急於加載)Transaction.product.photo(如果產品為PhysicalProduct)和Transaction.product.provider(如果產品為Service)? 如前所述,嘗試僅通過一個查詢來實現這一目標。
我嘗試了以下方法:
// This is conceptually what I want to achieve.
// Not very surprisingly, this will throw an InvalidCastException
Transactions
.Include(x => ((PhysicalProduct)x.product).photo)
.Include(x => ((Service)x.product).provider)
.ToList();
// Based on http://stackoverflow.com/questions/7635152/entity-framework-eager-loading-of-subclass-related-objects
// Projection into an anonymous type, then transform back.
// doesn't work though, throws an InvalidOperationException, e.g.
// The property "photo" on entity type "Product" could not be found. Ensure that the property exists and has been included in the model.
// i.e. even though I wrapped this in a condition (x.product is PhysicalProduct), seems like EntityFramework still tries to execute or parse the statement thereafter even if the condition is not true.
var query = Transactions.Select(x => new
{
_transaction = x,
_physicalProductPhoto = (x.product is PhysicalProduct) ? ((PhysicalProduct)x.product).photo : null;
_serviceProvider = (x.product is Service) ? ((Service)x.product).provider : null;
})
.ToList() // Execute query. Exception will be thrown at this step.
.Select(x =>
{
var result = x._transaction;
if (x.product is PhysicalProduct)
((PhysicalProduct)x.product).photo = x._physicalProductPhoto;
else if(x.product is Service)
((Service)x.product).provider = x._serviceProvider;
return result;
})
.ToList();
誰能想到實現這一目標的方法? 謝謝!
昨天,我在EF6- EF Eager獲取派生類中遇到了類似問題。 目前,EF Core在這方面並不更好-實際上,情況更糟,因為從3種EF6解決方法中,只有#2可以在這里工作。
解決方法是:
絕對不能通過單個查詢來完成。 您需要執行主查詢並在內存中具體化結果。 然后,對於每種派生的導航類型,收集PK並執行由這些鍵過濾的查詢。 最后,由於EF導航屬性修復,您將最終加載了所有導航屬性。
var transactions = db.Transactions.Include(e => e.product).ToList();
var productIds = transactions.Where(e => e.product is PhysicalProduct)
.Select(e => e.product.Id).Distinct();
db.BaseProducts.OfType<PhysicalProduct>().Include(e => e.photo)
.Where(e => productIds.Contains(e.Id)).Load();
var serviceIds = transactions.Where(e => e.product is Service)
.Select(e => e.product.Id).Distinct();
db.BaseProducts.OfType<Service>().Include(e => e.provider)
.Where(e => serviceIds.Contains(e.Id)).Load();
EF Core尚不支持此功能。 請參閱https://github.com/aspnet/EntityFramework/issues/3910了解跟蹤它的問題。
我相信唯一的解決方法是執行多個查詢,然后讓EF上下文為您完成修復。
我相信從鏈接的文檔中可以得知,通過使用“ ThenInclude”。 您能夠做到這一點。 抱歉,但我自己沒有嘗試過,因此無法驗證它是否有效。
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ThenInclude(post => post.Author)
.ThenInclude(author => author.Photo)
.Include(blog => blog.Owner)
.ThenInclude(owner => owner.Photo)
.ToList();
https://docs.efproject.net/en/latest/querying/related-data.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.