咱們知道C#中的TimeSpan對應SQL Server數據庫中的Time類型,可是若是由於特殊需求數據庫存儲的不是Time類型,而是做爲字符串,那麼咱們如何在查詢數據時對數據庫所存儲的字符串類型進行比較呢?git
首先咱們來看看正常狀況下屬性爲TimeSpan類型進行比較的狀況,給出以下實體模型。github
public class TestA { public int Id { get; set; } public string StrartEnd { get; set; } public string EndTime { get; set; } public TimeSpan TimeSpanStartEnd { get; set; } public TimeSpan TimeSpanEndTime { get; set; } }
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var testA = new TestA() { StrartEnd = "10:00:00", EndTime = "22:59:00", TimeSpanStartEnd = new TimeSpan(10, 00, 00), TimeSpanEndTime = new TimeSpan(22, 59, 00) }; ctx.TestAs.Add(testA); ctx.SaveChanges(); };
如上正常流程添加數據到數據庫中,接下來咱們來查詢數據利用TimeSpanStartEnd和TimeSpanEndTime,以下:數據庫
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var test = ctx.TestAs.Where(d => d.TimeSpanStartEnd >= DateTime.Now.TimeOfDay && DateTime.Now.TimeOfDay <= d.TimeSpanStartEnd).ToList(); };
竟然不支持TimeOfDay,須要初始化值設定項,那咱們接下來初始化TimeSpan看看:spa
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var time = new TimeSpan(9, 00, 00); var test = ctx.TestAs.Where(d => d.TimeSpanStartEnd >= time && time <= d.TimeSpanStartEnd).ToList(); };
到此咱們能夠下一結論:在EF 6.x中對TimeSpan進行查詢比較須要初始化TimeSpan值才行,不然拋出異常。問題來了,有一位園友問我,若是數據庫存儲的類型不是Time,而是字符串那麼咱們該如何查詢比較呢?當時內心第一想法明明能夠存儲Time,爲什麼要搞個字符串類型,結果問其緣由是特殊需求,好吧,那沒辦法,那咱們接下來探討一下如何,請往下看,咱們利用屬性StartEnd和EndTime來查詢。翻譯
此時咱們首先須要將數據庫中的字符串即StartEnd和EndTime轉換爲TimeSpan而後進行過濾,以下:3d
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var time = new TimeSpan(9, 00, 00); var test = ctx.TestAs.Where(d => TimeSpan.Parse(d.StrartEnd) >= time && time <= TimeSpan.Parse(d.EndTime)).ToList(); };
拋出異常沒法支持TimeSpan中的Parse解析,也就是說EF 6.x沒法將Parse進行翻譯。在EF 6.x中對日期相關操做有SqlFunctions和DbFunctions,最終通過對相關APi的嘗試,咱們可經過以下改造就行,不知是否有更好的辦法,一個簡單的過濾,其代碼實在有點多,直接上代碼:code
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var time = new TimeSpan(9, 00, 00); var test = ctx.TestAs.Where(d => (( DbFunctions.CreateTime( SqlFunctions.DatePart("hh", d.StrartEnd), SqlFunctions.DatePart("mi", d.StrartEnd), SqlFunctions.DatePart("ss", d.StrartEnd))) >= DbFunctions.CreateTime( SqlFunctions.DatePart("hh", time), SqlFunctions.DatePart("mi", time), SqlFunctions.DatePart("ss", time))) && (( DbFunctions.CreateTime( SqlFunctions.DatePart("hh", time), SqlFunctions.DatePart("mi", time), SqlFunctions.DatePart("ss", time))) <= DbFunctions.CreateTime( SqlFunctions.DatePart("hh", d.EndTime), SqlFunctions.DatePart("mi", d.EndTime), SqlFunctions.DatePart("ss", d.EndTime))) ).ToList(); };
好了,到了這裏算是給出了我在EF 6.x中實現的解決方案,Jeff在看待EF Core和EF 6.x習慣將兩者拿來比較,看看EF Core是否真的強大,咱們知道EF Core中沒有SqlFunctions和DbFunctions兩個APi,是否是就沒法實現了呢,咱們實踐便知,一樣是進行上述查詢。blog
using (var context = new EFCoreDbContext()) { var test = context.TestAs.Where(d => d.TimeSpanStartEnd >= DateTime.Now.TimeOfDay && DateTime.Now.TimeOfDay <= d.TimeSpanStartEnd).ToList(); }
咱們可以直接比較TimeSpan類型,此時咱們徹底不用初始化TimeSpan直接比較就行,從最終翻譯出來的SQL來看以及我在github上向EF Core團隊提交的ISSUE得出利用DaTime.Now.TimeOfDay會在客戶端被評估即在內存中查詢,可是在EF Core 2.1會被正確翻譯,詳情請見我提的ISSUE(https://github.com/aspnet/EntityFrameworkCore/issues/12187)。接下來咱們再來比較字符串即StartEnd和EndTime,以下:內存
using (var context = new EFCoreDbContext()) { var time = new TimeSpan(9, 00, 00); var test = context.TestAs.Where(d => TimeSpan.Parse(d.StrartEnd) >= time && time <= TimeSpan.Parse(d.EndTime)).ToList(); }
最終依然可以正常查詢沒有出現任何異常,相比較EF 6.x實現方式而言,代碼沒有那麼冗長,可是依然翻譯錯誤,不管第一種方式仍是第二種方式查詢在翻譯成SQL時都沒有添加篩選條件。字符串
在EF 6.x中對於TimeSpan類型的查詢必須經過TimeSpan初始化值,不然拋出異常,若是是字符串類型的TimeSpan那麼在查詢時須要藉助SqlFunctions和DbFunctions來實現,比較複雜,而對EF Core而言就和咱們正常查詢同樣,沒有任何異同,EF Core當前已經很穩定,仍是推薦你們早早使用EF Core和.NET Core,感謝您的閱讀。