SQL Server下如何用Entity Framework对比拆分日期时间与完整datetime字段
解决方案
错误原因
报错The property 'System.DateTime.Hour' has no setter的根源是:DateTime是.NET中的不可变值类型,所有时间属性(Hour/Minute/Second等)均为只读,无法直接赋值修改,只能通过构造函数、AddXXX系列方法生成新的DateTime实例。你直接在EF查询的表达式树中尝试修改Hour属性,既不符合C#语法,也无法被EF识别翻译为SQL语句。
可用实现方案
方案1:查询时直接构造匹配时间(无需修改模型)
直接在查询表达式中调用EF提供的内置函数,将拆分的日期+小时拼接为完整时间,EF会自动将逻辑翻译为SQL在数据库端执行,不会触发客户端报错。
EF Core 写法
// 假设拆分存储的表为TableA,日期字段为DateCol,小时字段为HourCol // 完整存储的表为TableB,时间字段为FullDateTimeCol var matchResult = dbContext.TableA .Join(dbContext.TableB, a => EF.Functions.DateAddHour(a.DateCol, (int)a.HourCol), b => b.FullDateTimeCol, (a, b) => new { A = a, B = b }) .ToList();
如果是LINQ查询语法写法:
var query = from a in dbContext.TableA join b in dbContext.TableB on EF.Functions.DateAddHour(a.DateCol, (int)a.HourCol) equals b.FullDateTimeCol select new { a, b }; var matchResult = query.ToList();
EF6 写法
var matchResult = dbContext.TableA .Join(dbContext.TableB, a => DbFunctions.AddHours(a.DateCol, (int)a.HourCol), b => b.FullDateTimeCol, (a, b) => new { A = a, B = b }) .ToList();
方案2:模型层封装计算属性(简化后续查询)
如果需要频繁做时间匹配,可以在实体模型中新增封装属性,配置EF自动映射为数据库计算逻辑,后续查询可以直接做等值比较:
- 实体类新增属性
public class TableA { public DateTime DateCol { get; set; } public byte HourCol { get; set; } // 新增封装的完整时间属性 public DateTime FullDateTime => DateCol.AddHours(HourCol); }
- EF Core 配置映射(写在DbContext的OnModelCreating方法中)
modelBuilder.Entity<TableA>() .Property(e => e.FullDateTime) .HasComputedColumnSql("DATEADD(hour, HourCol, DateCol)");
- 后续查询直接比较即可
var matchResult = dbContext.TableA .Join(dbContext.TableB, a => a.FullDateTime, b => b.FullDateTimeCol, (a, b) => new { A = a, B = b }) .ToList();
注意事项
所有时间比较逻辑必须放在IQueryable的查询表达式中,不要先将数据加载到内存再做匹配,否则会触发全表扫描,性能极差。
内容的提问来源于stack exchange,提问作者Antonio Parroni
相关产品推荐
相关产品推荐

