繁体   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