我正在做一個購物車的大數據庫調用。它包含許多關係,所有關係都使用.Include()
方法指定。只包含內容實體框架
現在我只想要EF包含我指定的內容。當我包含一個集合時,它會自動加載集合的關係。
所以我有一個ShoppingCart
,購物車有一個集合,如果ShoppingCartProducts
和那個有關係回到ShoppingCart
和Product
。
所以我想包括產品,但不購物車了,所以我做的:
IQueryable<ShoppingCart> query = DbContext.ShoppingCarts
.Include(p => p.ShoppingCartProducts)
.Include(p => p.ShoppingCartProducts.Select(x => x.Product))
後來我執行.FirstOrDefault()
其執行查詢。通過這個調試,它還包括每個ShoppingCartProducts
中的ShoppingCart
。
這聽起來有點小,但實際上在整個應用程序中都是這樣。新體系結構將實體對象轉換爲具有不同靜態方法和擴展的模型。最終導致StackoverflowException,因爲它遞歸地包含它的關係。
那麼我如何只有包括我所包含的內容?
我已將LazyLoadingEnabled
設爲false,並將ProxyCreationEnabled
設爲false。而我的收藏/評論並沒有標記爲virtual
。
經過這些問題的答案:
DBContext lazyloadingenabled set to true still loads related entities by default 對包括集合這是事實,但是一旦集合包括在內,該集合將加載所有其他的關係(我猜)
Entity Framework with Proxy Creation and Lazy Loading disabled is still loading child objects 幾乎相同的問題,但不是一個好的答案,只是一個解釋
EF 6 Lazy Loading Disabled but Child Record Loads Anyway 使用分離沒有幫助。
編輯:
正如EVK提到的,有事情做與EF自動填充爲已知關係的空白。現在問題實際上是如何關閉它。
編輯2:
所以從EVK的答案和我自己的解決方法後,我們瞭解到這些解決方案並沒有解決的大畫面。讓我試着解釋:
這些擴展和ConvertToModel
方法在每個存儲庫中實現,並且只要與它有關係就會相互調用。這個概念其實很好:如果你有關係,就轉換成模型,如果你沒有,就不要做任何事情。然而,由於這個EF'錯誤',我知道所有已知的關係到處都是。
以下是我們的解決方案無法正常工作的示例。對於這種情況,代碼將首先調用ConvertToModel
,然後再調用ShoppingCart
。但當然它可能是反之亦然。
ShoppingCartRepository
public static ShoppingCartModel ConvertToModel(ShoppingCart entity)
{
if (entity == null) return null;
ShoppingCartModel model = new ShoppingCartModel
{
Coupons = entity.ShoppingCardCoupons?.SelectShoppingCouponModel(typeof(ShoppingCart)),
Products = entity.ShoppingCartProducts?.SelectShoppingCartProductModel(typeof(ShoppingCart)),
};
return model;
}
ShoppingCartProductRepository
public static IEnumerable<ShoppingCartProductModel> SelectShoppingCartProductModel(this IEnumerable<ShoppingCartProduct> source, Type objSource = null)
{
bool includeRelations = source.GetType() != typeof(DbQuery<ShoppingCartProduct>);
return source.Select(x => new ShoppingCartProductModel
{
ShoppingCart = includeRelations && objSource != typeof(ShoppingCart) ? ShoppingCartRepository.ConvertToModel(x.ShoppingCart) : null,
ShoppingCartCoupons = includeRelations && objSource != typeof(ShoppingCartCoupon) ? x.ShoppingCartCoupons?.SelectShoppingCouponModel(typeof(ShoppingCartProduct)) : null,
});
}
ShoppingCartCouponRepository
public static IEnumerable<ShoppingCartCouponModel> SelectShoppingCouponModel(this IEnumerable<ShoppingCartCoupon> source, Type objSource = null)
{
bool includeRelations = source.GetType() != typeof(DbQuery<ShoppingCartCoupon>);
return source.Select(x => new ShoppingCartCouponModel
{
ShoppingCart = includeRelations && objSource != typeof(ShoppingCart) ? ShoppingCartRepository.ConvertToModel(x.ShoppingCart) : null,
ShoppingCartProduct = includeRelations && objSource != typeof(ShoppingCartProductModel) ? ShoppingCartProductRepository.ConvertToModel(x.ShoppingCartProduct) : null
});
}
當你學習它時,你會發現它可以從ShoppingCart
到ShoppingCartProduct
到ShoppingCartCoupon
回到ShoppingCart
。
我目前的解決方法是找出聚合根,並選擇哪一個需要哪一個。但我寧願有一個優雅的解決方案來解決這個問題。最好的做法是防止EF加載這些已知關係,或者以某種方式確定某個屬性是否以這種方式加載(反射?)。
EF在您的情況下不會從數據庫加載相關實體。對於每個ShoppingCartProduct,相關的ShoppingCart都是已知的 - 這就是您正在查詢的購物車。這個ShoppingCart已經加載到上下文中,這就是EF填充ShoppingCartProduct的ShoppingCart屬性的原因 - 它已經被加載並且已知並且無需加載任何東西。我不知道有什麼辦法來禁用這種(相當合理的)行爲。 – Evk
好點,這有助於理解'問題'。更新了答案。 – CularBytes
我認爲你將不得不修改你的擴展方法,通過跟蹤你已經訪問過的實體並忽略它們(不轉換爲模型)來防止堆棧溢出。或者不要忽略,但要像EF那樣做 - 用你已經轉換成模型的實體代替。 – Evk