From 828d0de10614efab7172048b934d00e3aed09719 Mon Sep 17 00:00:00 2001 From: Roman Marusyk Date: Wed, 8 Jan 2020 23:51:42 +0200 Subject: [PATCH] Add DATEFROMPARTS function to SqlServer (#19400) Add DATEFROMPARTS function to SqlServer --- .../SqlServerDbFunctionsExtensions.cs | 112 ++++++++ ...rverDateTimeFromPartsFunctionTranslator.cs | 44 --- .../SqlServerFromPartsFunctionTranslator.cs | 105 +++++++ .../SqlServerMethodCallTranslatorProvider.cs | 4 +- .../NorthwindDbFunctionsQuerySqlServerTest.cs | 257 ++++++++++++++++++ 5 files changed, 476 insertions(+), 46 deletions(-) delete mode 100644 src/EFCore.SqlServer/Query/Internal/SqlServerDateTimeFromPartsFunctionTranslator.cs create mode 100644 src/EFCore.SqlServer/Query/Internal/SqlServerFromPartsFunctionTranslator.cs diff --git a/src/EFCore.SqlServer/Extensions/SqlServerDbFunctionsExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerDbFunctionsExtensions.cs index 6c2995a9e7b..7f0204fabb5 100644 --- a/src/EFCore.SqlServer/Extensions/SqlServerDbFunctionsExtensions.cs +++ b/src/EFCore.SqlServer/Extensions/SqlServerDbFunctionsExtensions.cs @@ -1007,5 +1007,117 @@ public static DateTime DateTimeFromParts( int second, int millisecond) => throw new InvalidOperationException(SqlServerStrings.FunctionOnClient(nameof(DateTimeFromParts))); + + /// + /// Initializes a new instance of the structure to the specified year, month, day. + /// Corresponds to the SQL Server's DATEFROMPARTS(year, month, day). + /// + /// The DbFunctions instance. + /// The year (1753 through 9999). + /// The month (1 through 12). + /// The day (1 through the number of days in month). + /// New instance of the structure to the specified year, month, day. + public static DateTime DateFromParts( + [CanBeNull] this DbFunctions _, + int year, + int month, + int day) + => throw new InvalidOperationException(SqlServerStrings.FunctionOnClient(nameof(DateFromParts))); + + /// + /// Initializes a new instance of the structure to the specified year, month, day, hour, minute, second, fractions, and precision. + /// Corresponds to the SQL Server's DATETIME2FROMPARTS (year, month, day, hour, minute, seconds, fractions, precision). + /// + /// The DbFunctions instance. + /// The year (1753 through 9999). + /// The month (1 through 12). + /// The day (1 through the number of days in month). + /// The hours (0 through 23). + /// The minutes (0 through 59). + /// The seconds (0 through 59). + /// The fractional seconds (0 through 9999999). + /// The precision of the datetime2 value (0 through 7). + /// New instance of the structure to the specified year, month, day, hour, minute, second, fractions, and precision. + public static DateTime DateTime2FromParts( + [CanBeNull] this DbFunctions _, + int year, + int month, + int day, + int hour, + int minute, + int second, + int fractions, + int precision) + => throw new InvalidOperationException(SqlServerStrings.FunctionOnClient(nameof(DateTime2FromParts))); + + /// + /// Initializes a new instance of the structure to the specified year, month, day, hour, minute, second, fractions, hourOffset, minuteOffset and precision. + /// Corresponds to the SQL Server's DATETIMEOFFSETFROMPARTS (year, month, day, hour, minute, seconds, fractions, hour_offset, minute_offset, precision). + /// + /// The DbFunctions instance. + /// The year (1753 through 9999). + /// The month (1 through 12). + /// The day (1 through the number of days in month). + /// The hours (0 through 23). + /// The minutes (0 through 59). + /// The seconds (0 through 59). + /// The fractional seconds (0 through 9999999). + /// The hour portion of the time zone offset (-14 through +14). + /// The minute portion of the time zone offset (0 or 30). + /// The precision of the datetimeoffset value (0 through 7). + /// New instance of the structure to the specified year, month, day, hour, minute, second, fractions, hourOffset, minuteOffset and precision. + public static DateTimeOffset DateTimeOffsetFromParts( + [CanBeNull] this DbFunctions _, + int year, + int month, + int day, + int hour, + int minute, + int second, + int fractions, + int hourOffset, + int minuteOffset, + int precision) + => throw new InvalidOperationException(SqlServerStrings.FunctionOnClient(nameof(DateTimeOffsetFromParts))); + + /// + /// Initializes a new instance of the structure to the specified year, month, day, hour and minute. + /// Corresponds to the SQL Server's SMALLDATETIMEFROMPARTS (year, month, day, hour, minute). + /// + /// The DbFunctions instance. + /// The year (1753 through 9999). + /// The month (1 through 12). + /// The day (1 through the number of days in month). + /// The hours (0 through 23). + /// The minutes (0 through 59). + /// New instance of the structure to the specified year, month, day, hour and minute. + public static DateTime SmallDateTimeFromParts( + [CanBeNull] this DbFunctions _, + int year, + int month, + int day, + int hour, + int minute) + => throw new InvalidOperationException(SqlServerStrings.FunctionOnClient(nameof(SmallDateTimeFromParts))); + + /// + /// Initializes a new instance of the structure to the specified hour, minute, second, fractions, and precision. + /// Corresponds to the SQL Server's TIMEFROMPARTS (hour, minute, seconds, fractions, precision). + /// + /// The DbFunctions instance. + /// The hours (0 through 23). + /// The minutes (0 through 59). + /// The seconds (0 through 59). + /// The fractional seconds (0 through 9999999). + /// The precision of the time value (0 through 7). + /// New instance of the structure to the specified hour, minute, second, fractions, and precision. + public static TimeSpan TimeFromParts( + [CanBeNull] this DbFunctions _, + int hour, + int minute, + int second, + int fractions, + int precision) + => throw new InvalidOperationException(SqlServerStrings.FunctionOnClient(nameof(TimeFromParts))); } } diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerDateTimeFromPartsFunctionTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerDateTimeFromPartsFunctionTranslator.cs deleted file mode 100644 index f0e8a2845b4..00000000000 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerDateTimeFromPartsFunctionTranslator.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Query.SqlExpressions; -using Microsoft.EntityFrameworkCore.Storage; - -namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal -{ - public class SqlServerDateTimeFromPartsFunctionTranslator : IMethodCallTranslator - { - private readonly ISqlExpressionFactory _sqlExpressionFactory; - private readonly IRelationalTypeMappingSource _typeMappingSource; - - private static readonly MethodInfo _methodInfo = typeof(SqlServerDbFunctionsExtensions) - .GetRuntimeMethod(nameof(SqlServerDbFunctionsExtensions.DateTimeFromParts), new[] { typeof(DbFunctions), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }); - - public SqlServerDateTimeFromPartsFunctionTranslator( - [NotNull] ISqlExpressionFactory sqlExpressionFactory, - [NotNull] IRelationalTypeMappingSource typeMappingSource) - { - _sqlExpressionFactory = sqlExpressionFactory; - _typeMappingSource = typeMappingSource; - } - - public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList arguments) - { - return _methodInfo.Equals(method) - ? _sqlExpressionFactory.Function( - "DATETIMEFROMPARTS", - arguments.Skip(1), - _methodInfo.ReturnType, - _typeMappingSource.FindMapping(typeof(DateTime), "datetime")) - : null; - } - } -} - -// diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerFromPartsFunctionTranslator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerFromPartsFunctionTranslator.cs new file mode 100644 index 00000000000..ad7c24bea29 --- /dev/null +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerFromPartsFunctionTranslator.cs @@ -0,0 +1,105 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.Storage; + +namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal +{ + public class SqlServerFromPartsFunctionTranslator : IMethodCallTranslator + { + private readonly ISqlExpressionFactory _sqlExpressionFactory; + private readonly IRelationalTypeMappingSource _typeMappingSource; + + private static readonly MethodInfo _dateFromPartsMethodInfo = typeof(SqlServerDbFunctionsExtensions) + .GetRuntimeMethod(nameof(SqlServerDbFunctionsExtensions.DateFromParts), new[] { typeof(DbFunctions), typeof(int), typeof(int), typeof(int) }); + + private static readonly MethodInfo _dateTimeFromPartsMethodInfo = typeof(SqlServerDbFunctionsExtensions) + .GetRuntimeMethod(nameof(SqlServerDbFunctionsExtensions.DateTimeFromParts), new[] { typeof(DbFunctions), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }); + + private static readonly MethodInfo _dateTime2FromPartsMethodInfo = typeof(SqlServerDbFunctionsExtensions) + .GetRuntimeMethod(nameof(SqlServerDbFunctionsExtensions.DateTime2FromParts), new[] { typeof(DbFunctions), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }); + + private static readonly MethodInfo _dateTimeOffsetFromPartsMethodInfo = typeof(SqlServerDbFunctionsExtensions) + .GetRuntimeMethod(nameof(SqlServerDbFunctionsExtensions.DateTimeOffsetFromParts), new[] { typeof(DbFunctions), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }); + + private static readonly MethodInfo _smallDateTimeFromPartsMethodInfo = typeof(SqlServerDbFunctionsExtensions) + .GetRuntimeMethod(nameof(SqlServerDbFunctionsExtensions.SmallDateTimeFromParts), new[] { typeof(DbFunctions), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }); + + private static readonly MethodInfo _timeFromPartsMethodInfo = typeof(SqlServerDbFunctionsExtensions) + .GetRuntimeMethod(nameof(SqlServerDbFunctionsExtensions.TimeFromParts), new[] { typeof(DbFunctions), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }); + + public SqlServerFromPartsFunctionTranslator( + [NotNull] ISqlExpressionFactory sqlExpressionFactory, + [NotNull] IRelationalTypeMappingSource typeMappingSource) + { + _sqlExpressionFactory = sqlExpressionFactory; + _typeMappingSource = typeMappingSource; + } + + public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList arguments) + { + if (_dateFromPartsMethodInfo.Equals(method)) + { + return _sqlExpressionFactory.Function( + "DATEFROMPARTS", + arguments.Skip(1), + _dateFromPartsMethodInfo.ReturnType, + _typeMappingSource.FindMapping(typeof(DateTime), "date")); + } + + if (_dateTimeFromPartsMethodInfo.Equals(method)) + { + return _sqlExpressionFactory.Function( + "DATETIMEFROMPARTS", + arguments.Skip(1), + _dateTimeFromPartsMethodInfo.ReturnType, + _typeMappingSource.FindMapping(typeof(DateTime), "datetime")); + } + + if (_dateTime2FromPartsMethodInfo.Equals(method)) + { + return _sqlExpressionFactory.Function( + "DATETIME2FROMPARTS", + arguments.Skip(1), + _dateTime2FromPartsMethodInfo.ReturnType, + _typeMappingSource.FindMapping(typeof(DateTime), "datetime2")); + } + + if (_dateTimeOffsetFromPartsMethodInfo.Equals(method)) + { + return _sqlExpressionFactory.Function( + "DATETIMEOFFSETFROMPARTS", + arguments.Skip(1), + _dateTimeOffsetFromPartsMethodInfo.ReturnType, + _typeMappingSource.FindMapping(typeof(DateTimeOffset), "datetimeoffset")); + } + + if (_smallDateTimeFromPartsMethodInfo.Equals(method)) + { + return _sqlExpressionFactory.Function( + "SMALLDATETIMEFROMPARTS", + arguments.Skip(1), + _smallDateTimeFromPartsMethodInfo.ReturnType, + _typeMappingSource.FindMapping(typeof(DateTime), "smalldatetime")); + } + + if (_timeFromPartsMethodInfo.Equals(method)) + { + return _sqlExpressionFactory.Function( + "TIMEFROMPARTS", + arguments.Skip(1), + _timeFromPartsMethodInfo.ReturnType, + _typeMappingSource.FindMapping(typeof(TimeSpan), "time")); + } + + return null; + } + } +} diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs index 21fb37232fc..502db911571 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerMethodCallTranslatorProvider.cs @@ -19,14 +19,14 @@ public SqlServerMethodCallTranslatorProvider([NotNull] RelationalMethodCallTrans new SqlServerByteArrayMethodTranslator(sqlExpressionFactory), new SqlServerConvertTranslator(sqlExpressionFactory), new SqlServerDateDiffFunctionsTranslator(sqlExpressionFactory), - new SqlServerDateTimeFromPartsFunctionTranslator(sqlExpressionFactory, typeMappingSource), new SqlServerDateTimeMethodTranslator(sqlExpressionFactory), + new SqlServerFromPartsFunctionTranslator(sqlExpressionFactory, typeMappingSource), new SqlServerFullTextSearchFunctionsTranslator(sqlExpressionFactory), new SqlServerIsDateFunctionTranslator(sqlExpressionFactory), new SqlServerMathTranslator(sqlExpressionFactory), new SqlServerNewGuidTranslator(sqlExpressionFactory), new SqlServerObjectToStringTranslator(sqlExpressionFactory), - new SqlServerStringMethodTranslator(sqlExpressionFactory) + new SqlServerStringMethodTranslator(sqlExpressionFactory), }); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServerTest.cs index fba3bd9c20e..5519758014d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindDbFunctionsQuerySqlServerTest.cs @@ -740,6 +740,263 @@ FROM [Orders] AS [o] } } + [ConditionalFact] + public virtual void DateFromParts_column_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => c.OrderDate > EF.Functions.DateFromParts(DateTime.Now.Year, 12, 31)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE [o].[OrderDate] > DATEFROMPARTS(DATEPART(year, GETDATE()), 12, 31)"); + } + } + + [ConditionalFact] + public virtual void DateFromParts_constant_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => new DateTime(2018, 12, 29) > EF.Functions.DateFromParts(DateTime.Now.Year, 12, 31)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE '2018-12-29' > DATEFROMPARTS(DATEPART(year, GETDATE()), 12, 31)"); + } + } + + [ConditionalFact] + public virtual void DateFromParts_compare_with_local_variable() + { + var date = new DateTime(1919, 12, 12); + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => date > EF.Functions.DateFromParts(DateTime.Now.Year, date.Month, date.Day)); + + Assert.Equal(0, count); + + AssertSql( + @$"@__date_0='1919-12-12T00:00:00' (DbType = Date) +@__date_Month_2='12' +@__date_Day_3='12' + +SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE @__date_0 > DATEFROMPARTS(DATEPART(year, GETDATE()), @__date_Month_2, @__date_Day_3)"); + } + } + + [ConditionalFact] + public virtual void DateTime2FromParts_column_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => c.OrderDate > EF.Functions.DateTime2FromParts(DateTime.Now.Year, 12, 31, 23, 59, 59, 999, 3)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE [o].[OrderDate] > DATETIME2FROMPARTS(DATEPART(year, GETDATE()), 12, 31, 23, 59, 59, 999, 3)"); + } + } + + [ConditionalFact] + public virtual void DateTime2FromParts_constant_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => new DateTime(2018, 12, 29, 23, 20, 40) > EF.Functions.DateTime2FromParts(DateTime.Now.Year, 12, 31, 23, 59, 59, 9999999, 7)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE '2018-12-29T23:20:40.0000000' > DATETIME2FROMPARTS(DATEPART(year, GETDATE()), 12, 31, 23, 59, 59, 9999999, 7)"); + } + } + + [ConditionalFact] + public virtual void DateTime2FromParts_compare_with_local_variable() + { + var dateTime = new DateTime(1919, 12, 12, 10, 20, 15); + int fractions = 9999999; + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => dateTime > EF.Functions.DateTime2FromParts(DateTime.Now.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, fractions, 7)); + + Assert.Equal(0, count); + + AssertSql( + @$"@__dateTime_0='1919-12-12T10:20:15' +@__dateTime_Month_2='12' +@__dateTime_Day_3='12' +@__dateTime_Hour_4='10' +@__dateTime_Minute_5='20' +@__dateTime_Second_6='15' +@__fractions_7='9999999' + +SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE @__dateTime_0 > DATETIME2FROMPARTS(DATEPART(year, GETDATE()), @__dateTime_Month_2, @__dateTime_Day_3, @__dateTime_Hour_4, @__dateTime_Minute_5, @__dateTime_Second_6, @__fractions_7, 7)"); + } + } + + [ConditionalFact] + public virtual void DateTimeOffsetFromParts_column_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => c.OrderDate > EF.Functions.DateTimeOffsetFromParts(DateTime.Now.Year, 12, 31, 23, 59, 59, 5, 12, 30, 1)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE CAST([o].[OrderDate] AS datetimeoffset) > DATETIMEOFFSETFROMPARTS(DATEPART(year, GETDATE()), 12, 31, 23, 59, 59, 5, 12, 30, 1)"); + } + } + + [ConditionalFact] + public virtual void DateTimeOffsetFromParts_constant_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => new DateTimeOffset(2018, 12, 29, 23, 20, 40, new TimeSpan(1, 0, 0)) > EF.Functions.DateTimeOffsetFromParts(DateTime.Now.Year, 12, 31, 23, 59, 59, 50, 1, 0, 7)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE '2018-12-29T23:20:40.0000000+01:00' > DATETIMEOFFSETFROMPARTS(DATEPART(year, GETDATE()), 12, 31, 23, 59, 59, 50, 1, 0, 7)"); + } + } + + [ConditionalFact] + public virtual void DateTimeOffsetFromParts_compare_with_local_variable() + { + var dateTimeOffset = new DateTimeOffset(1919, 12, 12, 10, 20, 15, new TimeSpan(1, 30, 0)); + int fractions = 5; + int hourOffset = 1; + int minuteOffset = 30; + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => dateTimeOffset > EF.Functions.DateTimeOffsetFromParts(DateTime.Now.Year, dateTimeOffset.Month, dateTimeOffset.Day, dateTimeOffset.Hour, dateTimeOffset.Minute, dateTimeOffset.Second, fractions, hourOffset, minuteOffset, 7)); + + Assert.Equal(0, count); + + AssertSql( + @$"@__dateTimeOffset_0='1919-12-12T10:20:15.0000000+01:30' +@__dateTimeOffset_Month_2='12' +@__dateTimeOffset_Day_3='12' +@__dateTimeOffset_Hour_4='10' +@__dateTimeOffset_Minute_5='20' +@__dateTimeOffset_Second_6='15' +@__fractions_7='5' +@__hourOffset_8='1' +@__minuteOffset_9='30' + +SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE @__dateTimeOffset_0 > DATETIMEOFFSETFROMPARTS(DATEPART(year, GETDATE()), @__dateTimeOffset_Month_2, @__dateTimeOffset_Day_3, @__dateTimeOffset_Hour_4, @__dateTimeOffset_Minute_5, @__dateTimeOffset_Second_6, @__fractions_7, @__hourOffset_8, @__minuteOffset_9, 7)"); + } + } + + [ConditionalFact] + public virtual void SmallDateTimeFromParts_column_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => c.OrderDate > EF.Functions.SmallDateTimeFromParts(DateTime.Now.Year, 12, 31, 12, 59)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE [o].[OrderDate] > SMALLDATETIMEFROMPARTS(DATEPART(year, GETDATE()), 12, 31, 12, 59)"); + } + } + + [ConditionalFact] + public virtual void SmallDateTimeFromParts_constant_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => new DateTime(2018, 12, 29, 23, 20, 0) > EF.Functions.SmallDateTimeFromParts(DateTime.Now.Year, 12, 31, 12, 59)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE '2018-12-29T23:20:00' > SMALLDATETIMEFROMPARTS(DATEPART(year, GETDATE()), 12, 31, 12, 59)"); + } + } + + [ConditionalFact] + public virtual void SmallDateTimeFromParts_compare_with_local_variable() + { + var dateTime = new DateTime(1919, 12, 12, 23, 20, 0); + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => dateTime > EF.Functions.SmallDateTimeFromParts(DateTime.Now.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute)); + + Assert.Equal(0, count); + + AssertSql( + @$"@__dateTime_0='1919-12-12T23:20:00' (DbType = DateTime) +@__dateTime_Month_2='12' +@__dateTime_Day_3='12' +@__dateTime_Hour_4='23' +@__dateTime_Minute_5='20' + +SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE @__dateTime_0 > SMALLDATETIMEFROMPARTS(DATEPART(year, GETDATE()), @__dateTime_Month_2, @__dateTime_Day_3, @__dateTime_Hour_4, @__dateTime_Minute_5)"); + } + } + + [ConditionalFact] + public virtual void TimeFromParts_constant_compare() + { + using (var context = CreateContext()) + { + var count = context.Orders + .Count(c => new TimeSpan(23, 59, 0) > EF.Functions.TimeFromParts(23, 59, 59, c.OrderID % 60, 2)); + + Assert.Equal(0, count); + + AssertSql( + @"SELECT COUNT(*) +FROM [Orders] AS [o] +WHERE '23:59:00' > TIMEFROMPARTS(23, 59, 59, [o].[OrderID] % 60, 2)"); + } + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); }