Search code examples
c#linqlinq-to-sqltype-conversionexpression-trees

No coercion operator is defined between types 'System.Guid' and 'System.String'


I am building Expression tree for Linq-to-sql. In database on some of tables relevant columns are stored as string while some are stored as Guid. I have solved similar problem with int and int? by wrapping lambda constant with Expression.Convert(Expression.Constant(search.PolicyNumber), policyNumberColumnLambda.Type) (where PolicyNumber sometimes was nullable) which worked just fine. But it does not fly for Guid to string conversion apparently.

Code looks following:

public static IQueryable<IRetrieveGuid> SearchByRetrieveGuid<IRetrieveGuid>(this IQueryable<IRetrieveGuid> queryable, SearchModel search)
    {
        var paramLambda = Expression.Parameter(typeof(IRetrieveGuid));
        var columnLambda = Expression.Property(paramLambda, "retrieveguid");
        var lambda = Expression.Lambda<Func<IRetrieveGuid, bool>>(
            Expression.Equal(columnLambda, Expression.Convert(Expression.Constant(search.RetrieveGuid), columnLambda.Type)), paramLambda);
        return queryable.Where(lambda);
    }

How do I convert types to match in expression tree?


Solution

  • SOLUTION1:

    This is by a magnitude faster than solution2, however if you have variety of possibilities might result in long if else or switch statement

    var retrieveGuidAsString =  search.RetrieveGuid.ToString();
    var constantLambda = columnLambda.Type.Name == "Guid"  ? Expression.Constant(search.RetrieveGuid) : Expression.Constant(retrieveGuidAsString);
    var lambda = Expression.Lambda<Func<IRetrieveGuid, bool>>(Expression.Equal(columnLambda, constantLambda), paramLambda);
    

    SOLUTION2:

    This did work

    public static IQueryable<IRetrieveGuid> SearchByRetrieveGuid<IRetrieveGuid>(this IQueryable<IRetrieveGuid> queryable, SearchModel search)
        {
            var paramLambda = Expression.Parameter(typeof (IRetrieveGuid));
            var columnLambda = Expression.Property(paramLambda, "retrieveguid");
            var lambda = Expression.Lambda<Func<IRetrieveGuid, bool>>(
                Expression.Equal(columnLambda, Expression.Call(Expression.Convert(Expression.Constant(search.RetrieveGuid), typeof (object)), typeof (object).GetMethod("ToString"))), paramLambda);
            return queryable.Where(lambda);
        }
    

    but is incredibly slow as it produces following sql

    ([Extent1].[retrieveguid] = 'c87d1234-46ad-47bf-9a9c-d9a35a454bd5' as uniqueidentifier) AS nvarchar(max))))) OR (([Extent1].[retrieveguid] IS NULL) AND (LOWER( CAST( cast('c87d1234-46ad-47bf-9a9c-d9a35a454bd5' as uniqueidentifier) AS nvarchar(max))) IS NULL)))