Search code examples
c#subsoniclambdasimplerepository

Lambda Contains in SimpleRepository.Find


In SubSonic 3.04's SimpleRepository, I cannot seem to perform a Contains operation within a lambda expression. Here's a trivial example:

SimpleRepository repo = new SimpleRepository("ConnectionString");

List<int> userIds = new List<int>();
userIds.Add(1);
userIds.Add(3);

List<User> users = repo.Find<User>(x => userIds.Contains(x.Id)).ToList();

I get the error message:

variable 'x' of type 'User' referenced from scope '', but it is not defined

Am I missing something here, or does SubSonic not support Contains in lambda expressions? If not, how would this be done?


Solution

  • Since neither of these seem to work...

    x => guids.Contains(x.Guid)
    x => guids.Any(y => y == x.Guid)
    

    ... we write a custom lambda expression builder that generates:

    x => x.Id == {id1} OR x.Id == {id2} OR x.Id == {id3}
    

    This is a trivial scenario, but demonstrates how GetContainsId<User>(ids, repo) will find all Users with an Id that matches something in the supplied list.

    public List<T> GetContainsId<T>(List<int> ids, SimpleRepository repo)
        where T : Record, new() // `Record` is a base class with property Id
    {
        ParameterExpression x = Expression.Parameter(typeof(T), "x");
        LambdaExpression expr;
        if (ids.Count == 0)
        {
            expr = Expression.Lambda(LambdaExpression.Constant(false), x);
        }
        else
        {
            expr = Expression.Lambda(BuildEqual(x, ids.ToArray()), x);
        }
    
        return repo.Find<T>((Expression<Func<T,bool>>)expr).ToList();
    }
    
    private BinaryExpression BuildEqual(ParameterExpression x, int id)
    {
        MemberExpression left = Expression.Property(x, "Id");
        ConstantExpression right = Expression.Constant(id);
        return Expression.Equal(left, right);
    }
    
    private BinaryExpression BuildEqual(ParameterExpression x, int[] ids, int pos = 0)
    {
        int id = ids[pos];
        pos++;
    
        if (pos == ids.Length)
        {
            return BuildEqual(x, id);
        }
    
        return Expression.OrElse(BuildEqual(x, ids, pos), BuildEqual(x, id));
    }