如何将计算库存的PostgreSQL查询转为LINQ?含子查询可空比较
转换PostgreSQL查询到LINQ(含可空值处理)
首先先明确原SQL的核心逻辑:
取出所有
items记录,同时为每条Item计算一个stock值——统计指定日期内,tickets.starttime的日期等于目标日期、且时间部分和items.sessionstarttime的时间部分完全匹配的工单总数。
先假设你的实体类结构(如果和实际有出入,调整字段名即可)
// Items表对应的实体 public class Item { public int Id { get; set; } public DateTime? SessionStartTime { get; set; } // 对应sessionstarttime,假设字段可空 // 其他业务字段... } // Tickets表对应的实体 public class Ticket { public int Id { get; set; } public DateTime? StartTime { get; set; } // 对应starttime,假设字段可空 // 其他业务字段... }
方法1:查询语法(和原SQL结构最接近)
这种写法可读性高,完全对应原SQL的子查询逻辑:
// 目标日期作为参数传入(替代原SQL的硬编码值) DateTime targetDate = new DateTime(2018, 4, 6); var result = from item in dbContext.Items // 子查询计算当前Item对应的stock let stockCount = (from ticket in dbContext.Tickets where ticket.StartTime.HasValue // 先判断可空字段是否有值 && item.SessionStartTime.HasValue && ticket.StartTime.Value.Date == targetDate // 匹配目标日期 && ticket.StartTime.Value.TimeOfDay == item.SessionStartTime.Value.TimeOfDay // 匹配时间部分 select ticket).Count() select new { // 保留Item的所有字段 Item = item, // 新增Stock字段 Stock = stockCount };
方法2:方法语法(更简洁)
如果习惯链式调用的写法,可以用这个版本:
DateTime targetDate = new DateTime(2018, 4, 6); var result = dbContext.Items .Select(item => new { Item = item, Stock = dbContext.Tickets.Count(ticket => ticket.StartTime.HasValue && item.SessionStartTime.HasValue && ticket.StartTime.Value.Date == targetDate && ticket.StartTime.Value.TimeOfDay == item.SessionStartTime.Value.TimeOfDay) });
关键注意事项(解决可空值问题)
- 必须先判断可空字段的HasValue:LINQ to SQL会把这个判断转换成SQL中的空值检查(比如
IS NOT NULL),既避免空引用异常,也确保查询逻辑和原SQL一致。 - 时间部分匹配:用C#的
TimeOfDay属性对应SQL中的::time转换,LINQ to SQL会自动将其映射为对应的数据库时间比较逻辑。 - 参数化日期:把原SQL的硬编码日期改成变量传入,符合LINQ的参数化查询规范,也让代码更灵活复用。
如果你的时间字段是非可空的(DateTime而非DateTime?)
可以去掉HasValue的判断,简化代码:
var result = from item in dbContext.Items let stockCount = dbContext.Tickets.Count(ticket => ticket.StartTime.Date == targetDate && ticket.StartTime.TimeOfDay == item.SessionStartTime.TimeOfDay) select new { Item = item, Stock = stockCount };
可选:投影到自定义DTO
如果需要返回强类型的结果,而不是匿名类型,可以定义一个DTO类:
public class ItemWithStockDto { public int ItemId { get; set; } public DateTime SessionStartTime { get; set; } // 其他Item的业务字段... public int Stock { get; set; } } // 转换查询 var result = dbContext.Items .Select(item => new ItemWithStockDto { ItemId = item.Id, SessionStartTime = item.SessionStartTime.GetValueOrDefault(), // 处理可空值,或根据业务设置默认值 Stock = dbContext.Tickets.Count(ticket => ticket.StartTime.HasValue && item.SessionStartTime.HasValue && ticket.StartTime.Value.Date == targetDate && ticket.StartTime.Value.TimeOfDay == item.SessionStartTime.Value.TimeOfDay) });
内容的提问来源于stack exchange,提问作者Ernis
相关产品推荐
相关产品推荐

