Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DATEFROMPARTS function to SqlServer #19400

Merged
merged 11 commits into from
Jan 8, 2020
Merged

Conversation

Marusyk
Copy link
Member

@Marusyk Marusyk commented Dec 25, 2019

Contributes #19237

Add DATEFROMPARTS function

Please review,
Thank you in advance

@maumar
Copy link
Contributor

maumar commented Jan 3, 2020

@Marusyk please fix the failing test, ideally convert the added tests to AssertQuery pattern and add tests for each method (datetime2, datetimeoffset, smalldatetime, time). Looks good otherwise

@Marusyk
Copy link
Member Author

Marusyk commented Jan 5, 2020

Could anyone suggest?
I have problem with TimeFromParts :

var count = context.Orders
     .Count(c => new TimeSpan(23, 59, 0) > EF.Functions.TimeFromParts(12, 12, 31, 5, 1));

it throws

System.InvalidOperationException
HResult=0x80131509
Message=An exception was thrown while attempting to evaluate the LINQ query parameter expression '(new TimeSpan(23, 59, 0) > EF.Functions.TimeFromParts(12, 12, 31, 5, 1))'.
Source=Microsoft.EntityFrameworkCore
StackTrace:
at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.GetValue(Expression expression, String& parameterName) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\ParameterExtractingExpressionVisitor.cs:line 458
at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Evaluate(Expression expression, Boolean generateParameter) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\ParameterExtractingExpressionVisitor.cs:line 292
at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\ParameterExtractingExpressionVisitor.cs:line 110
at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression1 node) at System.Linq.Expressions.Expression1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\ParameterExtractingExpressionVisitor.cs:line 113
at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\ParameterExtractingExpressionVisitor.cs:line 113
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\ParameterExtractingExpressionVisitor.cs:line 113
at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.ExtractParameters(Expression expression) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\ParameterExtractingExpressionVisitor.cs:line 84
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExtractParameters(Expression query, IParameterValues parameterValues, IDiagnosticsLogger1 logger, Boolean parameterize, Boolean generateContextAccessors) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\QueryCompiler.cs:line 191 at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\QueryCompiler.cs:line 90 at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) in C:\Users\rmarusyk\source\EntityFrameworkCore\src\EFCore\Query\Internal\EntityQueryProvider.cs:line 79 at System.Linq.Queryable.Count[TSource](IQueryable1 source, Expression`1 predicate)
at Microsoft.EntityFrameworkCore.Query.NorthwindDbFunctionsQuerySqlServerTest.TimeFromParts_constant_compare() in C:\Users\rmarusyk\source\EntityFrameworkCore\test\EFCore.SqlServer.FunctionalTests\Query\NorthwindDbFunctionsQuerySqlServerTest.cs:line 1005

This exception was originally thrown at this call stack:
Microsoft.EntityFrameworkCore.SqlServerDbFunctionsExtensions.TimeFromParts(Microsoft.EntityFrameworkCore.DbFunctions, int, int, int, int, int) in SqlServerDbFunctionsExtensions.cs
Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.GetValue(System.Linq.Expressions.Expression, out string) in ParameterExtractingExpressionVisitor.cs

Inner Exception 1:
InvalidOperationException: The 'TimeFromParts' method is not supported because the query has switched to client-evaluation. Inspect the log to determine which query expressions are triggering client-evaluation.

@smitpatel
Copy link
Member

EF.Functions.TimeFromParts(12, 12, 31, 5, 1)

Use at least one argument which is range variable from server side. (i.e. using c)

@maumar
Copy link
Contributor

maumar commented Jan 7, 2020

how about:

Orders.Select(o => new { o.OrderID, Time = EF.Functions.TimeFromParts(12, 12, 31, 5, o.OrderId % 60) })

@maumar maumar merged commit 828d0de into dotnet:master Jan 8, 2020
@maumar
Copy link
Contributor

maumar commented Jan 8, 2020

@Marusyk thank you for the contribution!

public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList<SqlExpression> arguments)
{
if (_dateFromPartsMethodInfo.Equals(method))
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor to set function name and return server type using case block.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Should I create a new PR for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do it. I may have small clean up tasks in other unrelated PRs too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants