Pregunta

En SubSonic de 3,04 SimpleRepository, me parece que no puede realizar una operación de Contains dentro de una expresión lambda. Aquí está un ejemplo trivial:

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();

Me sale el mensaje de error:

variable de 'x' de tipo 'Usuario' hace referencia desde alcance '', pero no se define

Me estoy perdiendo algo aquí, o no SubSonic no soporta Contains en las expresiones lambda? Si no es así, ¿cómo se puede hacer?

¿Fue útil?

Solución

Dado que ninguno de los dos parece funcionar ...

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

... que escribir un generador de expresiones lambda personalizado que genera:

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

Este es un escenario trivial, sino que demuestra que GetContainsId<User>(ids, repo) encontrará todos los usuarios con un ID que coincide con algo en la lista proporcionada.

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));
}

Otros consejos

subsónico probablemente no es capaz de convertir el userIds.Contains porque es incapaz de traducir esa lista en algo que se puede ejecutar en una base de datos SQL. Es probable que tenga que recurrir a la definición de un explictely o condición:

repo.Find<User>(x => x.Id == 1 || x.Id == 3).ToList();

Estoy bastante seguro de que esto funcionará si se utiliza un IEnumerable en lugar de una lista. Por lo que el siguiente debería funcionar:

SimpleRepository repo = new SimpleRepository("ConnectionString");

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

List<User> users = repo.Find<User>(x => userIds.Contains(x.Id)).ToList();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top