Askolein Askolein - 2 months ago 8
C# Question

Use == operator with generic type in a Where Linq statement

I am trying to generate a SQL query (as a string) using the SQLinq library. The code context is a generic class that creates the query with a

Where
clause in it.

public string Get<TEntity, TId>(TId id)
where TEntity: IHasAnIdField<TId>
{
var query = new SQLinq<TEntity>();

// The following statement does not compile due to error in lambda with "==" operator
// "Operator '==' cannot be applied to operands of type 'TId' and 'TId'"
query = query.Where((Expression<Func<TEntity, bool>>)(i => i.Id == id));

var sql = query.ToSQL().ToQuery();
return sql;
}


Adding a
where TId: class
generic constraint resolves the problem but since my TId are in most cases value types (mainly
int
,
long
,
Guid
) it does not match my needs. And the generic constraint
where TId: struct
does not make it compile. I understand the reasons why this happens (thanks to this thread).

The interface for the entity is

public interface IHasAnIdField<TId>
{
TId Id { get; }
}


I cannot use a
.Equal(..)
call or any
EqualityComparer
since a method call in the Expression tree is not handled by the SQLinq tool.

How can I inform the compiler that my TId is compatible with the
==
operator?

Answer

You could build the expression manually:

public string Get<TEntity, TId>(TId id)
    where TEntity: IHasAnIdField<TId>
{
    var query = new SQLinq<TEntity>();

    // predicate: i => i.Id == id    
    var arg = Expression.Parameter(typeof(TEntity), "i");
    var predicate =
        Expression.Lambda<Func<TEntity, bool>>(
            Expression.Equal(
                Expression.Property(arg, "Id"),
                Expression.Constant(id))
            arg);


    query = query.Where(predicate);
    var sql = query.ToSQL().ToQuery();
    return sql;
}