如何在LINQ查询中实现CAST(ISNULL(字段,0) AS decimal(18,3))等效逻辑
解决方案
你可以通过投影查询(Select) 实现和原SQL完全一致的转换逻辑,这种方式不会加载多余字段,性能和原生SQL一致:
// 如果你需要返回和原查询一致的OwnerData实体,直接在Select中映射即可 var data = await _context.Set<OwnerProfile>() .Where(x => x.ThirdPartyRefId == ownerProfileId) .Select(x => new OwnerData { OwnerProfileId = x.OwnerProfileId, Email = x.Email, // 对应 CAST(ISNULL([OWB].[CustomBalance], 0) AS decimal(18, 3)) CustomBalance = Math.Round(x.OwnerBalance.CustomBalance ?? 0m, 3) }) .ToListAsync();
说明:
?? 0m对应SQL中的ISNULL逻辑,当CustomBalance为null时默认返回0Math.Round(xxx, 3)会被EF Core自动翻译为对应数据库的精度处理逻辑,最终生成的SQL会自带CAST(xxx AS decimal(18,3))的等价转换- 如果你的
OwnerBalances是1对多导航属性,调整为取对应单条记录即可:CustomBalance = Math.Round(x.OwnerBalances.FirstOrDefault()?.CustomBalance ?? 0m, 3)
注:如果你使用的是EF6而非EF Core,将
Math.Round替换为DbFunctions.Round即可正常翻译为SQL。
如果你需要严格指定精度为decimal(18,3),可以在实体模型配置中添加精度声明,EF会在查询和映射时自动适配:
// 在DbContext的OnModelCreating方法中添加 modelBuilder.Entity<OwnerData>() .Property(p => p.CustomBalance) .HasPrecision(18, 3);
如果你一定要保留Include加载全量导航属性的写法,可以在内存中做转换(性能略低,不推荐):
var rawData = await _context.Set<OwnerProfile>() .Include(x => x.OwnerBalances) .Where(x => x.ThirdPartyRefId == ownerProfileId) .ToListAsync(); var data = rawData.Select(x => new OwnerData { OwnerProfileId = x.OwnerProfileId, Email = x.Email, CustomBalance = Math.Round(x.OwnerBalances.FirstOrDefault()?.CustomBalance ?? 0m, 3) }).ToList();
内容的提问来源于stack exchange,提问作者user1765862
相关产品推荐
相关产品推荐

