特殊需求:EF 6.x如何比较TimeSpan格式的字符串?EF Core实现方式是否和EF 6.x等同?

前言

我们知道C#中的TimeSpan对应SQL Server数据库中的Time类型,但是如果因为特殊需求数据库存储的不是Time类型,而是作为字符串,那么我们如何在查询数据时对数据库所存储的字符串类型进行比较呢?

TimeSpan类型比较

首先我们来看看正常情况下属性为TimeSpan类型进行比较的情况,给出如下实体模型。

复制代码
    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看看:

复制代码
            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来查询。

EF 6.x如何比较TimeSpan格式的字符串?

此时我们首先需要将数据库中的字符串即StartEnd和EndTime转换为TimeSpan然后进行过滤,如下:

复制代码
            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的尝试,我们可通过如下改造就行,不知是否有更好的办法,一个简单的过滤,其代码实在有点多,直接上代码:

复制代码
            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,是不是就无法实现了呢,我们实践便知,同样是进行上述查询。

EF Core比较TimeSpan格式的字符串

            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,感谢您的阅读。


为了方便大家在移动端也能看到我分享的博文,现已注册个人公众号,扫描上方左边二维码即可,欢迎大家关注,有时间会及时分享相关技术博文。

感谢花时间阅读此篇文章,如果您觉得这篇文章你学到了东西也是为了犒劳下博主的码字不易不妨打赏一下吧,让楼主能喝上一杯咖啡,在此谢过了!
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
本文版权归作者和博客园共有,来源网址:http://www.cnblogs.com/CreateMyself)/欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   Jeffcky  阅读(1382)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2017-06-01 探讨SQL Server并发处理存在就更新七种解决方案
2016-06-01 AngularJS之中级Route【二】(七)
点击右上角即可分享
微信分享提示