Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 918
Askolein Avatar asked Mar 21 '14 14:03

Askolein


2 Answers

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;
}
like image 132
Thomas Levesque Avatar answered Sep 28 '22 00:09

Thomas Levesque


You should be able to use the new DynamicSQLinq class. Some examples can be seen in the unit tests for it that SQLinq has. In your case, it might look like:

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

    query = query.Where("Id = @0", id);

    var sql = query.ToSQL().ToQuery();
    return sql;
}
like image 22
Tim S. Avatar answered Sep 28 '22 01:09

Tim S.