views:

41

answers:

2

It is known generics do not support equality comparing if "class" restriction is not applied to a parameter. How can we workaround it for LINQ To Entities?

query.Where(p => p.CategoryId == categoryId); //doesn't work

The workaround I saw before was to use EqualityComparer.Default.Equal, but it can't be translated to SQL.

I also tried to build expression manually:

        var parameterExpression = Expression.Parameter(typeof(T));
        var categoryIdPropertyExpression = Expression.Property(parameterExpression, "CategoryId");
        var categoryIdExpression = Expression.Constant(categoryId);
        var equalityExpression = Expression.Equal(categoryIdPropertyExpression, categoryIdExpression);
        Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(equalityExpression, parameterExpression);

        query = query.Where(lambda);

My T may be long or Nullable. And this code throws an exception if T is Nullable as it can check equality of long and Nullable.

Are there any workarounds that work for EF.

A: 

Does this query work when you're using a nullable type?

query.Where(p =>
    (p.CategoryId == null && categoryId == null)
    || (p.CategoryId.Value == categoryId.Value));

Your original query more or less produces the following SQL:

SELECT *
FROM [Table]
WHERE [CategoryId] = @p0

My query produces:

SELECT *
FROM [Table]
WHERE (([CategoryId] IS NULL) AND (@p0 IS NULL)) OR ([CategoryId] = @p0)

The first query doesn't return results when categoryId is null, but the second one does.

As an alternative (which is less readable, but also works) you could try this:

from p in query
join a in new [] { categoryId } on p.CategoryId equals a 
select p;

Cheers.

Enigmativity
A: 

The solution that helped me: pass ParameterId as generic and change the line

var categoryIdExpression = Expression.Constant(categoryId);

to

var categoryIdExpression = Expression.Constant(categoryId, typeof(P));
Idsa