簡體   English   中英

Ef 返回 null,但實體存在

[英]Ef returning null, but entity exists

我正在嘗試在代碼中加載一些用戶信息,但 EF 返回 null。

foreach (var user in allAutoUsers)
{
    Wallet wallet = db.CabinetUsers
                      .Find(user.IdCabinetUser)?
                      .Wallets
                      .FirstOrDefault(x => x.TypeCurrency == currency);
}

可變用戶報告 1 個錢包,但是當我嘗試在上面的代碼中獲取它時,它返回 null。

有一些方法可以解決這個問題嗎?

閱讀更多 Linq 表達式,而不是依賴Find 如果實體之間的關系未定義為virtual關系,您可能會遇到問題,這會阻止 EF 延遲加載它們。

使用.Find()的問題在於,如果實體存在,它將返回實體,但是,嘗試訪問 DbContext 尚未意識到的任何相關屬性將需要延遲加載調用。 如果延遲加載被禁用,或者成員不是virtual ,這很容易被忽略,並且在啟用時可能是性能問題。

相反,Linq 可以讓你通過 object 圖表直接查詢得到你想要的:

foreach (var user in allAutoUsers)
{
    Wallet wallet = db.CabinetUsers
       .Where(x => x.IdCabinetUser == user.IdCabinetUser)
       .SelectMany(x => x.Wallets)
       .SingleOrDefault(x => x.TypeCurrency == currency);

   // do stuff with wallet...
}

這假設每個用戶只有 1 個指定貨幣的錢包。 當期望 0 或 1 時,使用SingleOrDefault 僅當您期望 0 或多個,想要“第一個”並指定OrderBy子句以確保第一個項目是可預測的時,才使用FirstOrDefault

這將導致每個用戶的查詢。 為所有用戶完成 1 個查詢:

var userIds = allAutoUsers.Select(x => x.IdCabinetUser).ToList();
var userWallets = db.CabinetUsers
       .Where(x => userIds.Contains(x.IdCabinetUser))
       .Select(x => new 
       {
          x.IdCabinetUser,
          Wallet = x.SelectMany(x => x.Wallets)
            .SingleOrDefault(x => x.TypeCurrency == currency);
       }).ToList();

因此,我會考慮使用Select擴展錢包SelectMany ,以獲取您真正關心的錢包中的詳細信息,而不是對整個錢包實體的引用。 這樣做的好處是可以加快查詢速度,減少 memory 的使用,並避免在 Wallet 引用稍后涉及的任何其他實體時潛在的延遲加載調用。

例如,如果您只需要 IdWallet、WalletName、TypeCurrency 和 Balance:

// replace this line from above...
          Wallet = x.SelectMany(x => x.Wallets)

// with ...
          Wallet = x.SelectMany(x => x.Wallets.Select(w => new 
          { 
              w.IdWallet,
              w.WalletName,
              w.TypeCurrency,
              w.Ballance
          }) // ...

從那里你可以在沒有額外查詢的情況下foreach你的內心需求:

foreach ( var userWallet in userWallets)
{
   // do stuff with userWallet.Wallet and userWallet.IdCabinetUser.
}

如果您想將錢包詳細信息返回給調用方法或視圖等,則不能為此使用匿名類型( new { } )。 相反,您需要為要返回的數據定義一個簡單的 class 並在其中使用Select new WalletDTO { IdWallet = w.IdWallet, //... }即使你使用 Entities,也建議將這些減少為 DTO 或 ViewModel,而不是返回實體。 實體不應該比產生它們的 DbContext “存活”更長的時間,否則會出現各種令人討厭的行為,例如ObjectDisposedException和序列化異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM