[英]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.