3
Vote

"Argument types do not match" error with Nullable DateTime ?? Operator

description

I have a problem when querying a condition using the ?? Operator on a Nullable<DateTime> property of my entity.

"result1" and "result2" work fine. "result3" throws an "Argument types do not match" exception.
  var result1 = context.Prospect_Task.Count(pt => (pt.sortOrder ?? 0) > 1);
  var result2 = context.Prospect_Task.Count(pt => pt.dueDate < DateTime.Now);
  var result3 = context.Prospect_Task.Count(pt => (pt.dueDate ?? DateTime.MaxValue) < DateTime.Now);
Perhaps it is related to this earlier issue:

https://effort.codeplex.com/workitem/701

The stacktrace is below.

System.Data.Entity.Core.EntityCommandExecutionException was unhandled by user code
HResult=-2146232004
Message=An error occurred while executing the command definition. See the inner exception for details.
Source=EntityFramework
StackTrace:
   at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
   at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
   at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3[TResult](IEnumerable`1 sequence)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
   at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
   at System.Linq.Queryable.Count[TSource](IQueryable`1 source, Expression`1 predicate)
   at QuickScreenAPITest.ProspectTests.ProspectsContext_CheckDashboardActiveProspects_Success() in c:\Projects\WebServices\QuickScreenAPI\QuickScreenAPITest\ProspectTests.cs:line 501
InnerException: System.ArgumentException
   HResult=-2147024809
   Message=Argument types do not match
   Source=System.Core
   StackTrace:
        at System.Linq.Expressions.Expression.Condition(Expression test, Expression ifTrue, Expression ifFalse)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbCaseExpression expression)
        at System.Data.Entity.Core.Common.CommandTrees.DbCaseExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbComparisonExpression expression)
        at System.Data.Entity.Core.Common.CommandTrees.DbComparisonExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbFilterExpression expression)
        at System.Data.Entity.Core.Common.CommandTrees.DbFilterExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbGroupByExpression expression)
        at System.Data.Entity.Core.Common.CommandTrees.DbGroupByExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbProjectExpression expression)
        at System.Data.Entity.Core.Common.CommandTrees.DbProjectExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
        at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
        at Effort.Internal.CommandActions.QueryCommandAction.ExecuteDataReader(ActionContext context)
        at Effort.Provider.EffortEntityCommand.ExecuteDbDataReader(CommandBehavior behavior)
        at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
        at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext`1 c)
        at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
        at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
        at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
        at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
        at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
   InnerException: 

comments

Tpancoast wrote Jan 8, 2015 at 6:33 PM

BTW, my original code did not actually need "?? DateTime.Max", so I was able to modify my code so it was similar to "result2" above. With this change I was able to create the test method using Effort without error. This issue is purely "FYI".

tamasflamich wrote Jan 12, 2015 at 9:28 PM

Thank you for reporting this issue! It seems to be easily fixed, so I may work on this soon.

mathiaskoerner wrote Apr 24, 2015 at 1:43 PM

The problem is the statement (nullableValue ?? defaultValue).
This will result in a DbCaseExpression of
When: nullableValue == NULL
Then: defaultValue [non-nullableType]
Else: nullableValue [as nullableType]

The problem for the Condition Expression is now: Else.Type != Then.Type

Our solution in TransformVisitor.Case.cs: Convert type of Else to type of Then
        public override Expression Visit(DbCaseExpression expression)
        {
            var expElse = this.Visit(expression.Else);
            List<Expression> cases = new List<Expression>() { expElse };

            for (int i = expression.When.Count - 1; i >= 0; i--)
            {
                var expWhen = this.Visit(expression.When[i]);
                var expThen = this.Visit(expression.Then[i]);

                // Special case: (nullableValue ?? defaultValue) will result in a DbCaseExpression of
                // When: nullableValue == NULL
                // Then: defaultValue
                // Else: nullableValue [with nullableType] (instead of nullableValue.Value)
                // Problem: Else.Type != Then.Type
                // Solution: Convert type of Else to type of Then

                // Could as well just convert Else to Then if only one When available
                if (expElse.Type != expThen.Type)
                {
                    // Convert (if possible; throws if not possible)
                    expThen = Expression.Convert(expThen, expElse.Type); // For example mentioned above, Then will now be Nullable
                }

                cases.Add(
                    Expression.Condition(
                        expWhen,
                        expThen,
                        cases.Last()));
            }

            return cases.Last();
        }

adolfo1981 wrote Aug 21, 2016 at 7:20 PM

Is the solution in TransformVisitor.Case.cs proposed by Mattias Koerner above in any of the Effort.EF6 releases?
Thanks,