2 votes

Contenus Lambda dans SimpleRepository.Find

Dans le SimpleRepository de SubSonic 3.04, je ne parviens pas à effectuer un Contains dans une expression lambda. Voici un exemple 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();

J'obtiens le message d'erreur suivant :

variable 'x' de type 'User' référencée à partir de la portée '', mais elle n'est pas définie

Ai-je raté quelque chose, ou SubSonic ne prend-il pas en charge Contains dans les expressions lambda ? Si ce n'est pas le cas, comment procéder ?

4voto

Anton Points 3129

Puisque aucune de ces solutions ne semble fonctionner...

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

... nous écrivons un constructeur d'expression lambda personnalisé qui génère :

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

Il s'agit d'un scénario trivial, mais qui démontre comment les GetContainsId<User>(ids, repo) trouvera tous les utilisateurs dont l'identifiant correspond à un élément de la liste fournie.

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

0voto

Thomas Points 3078

Subsonic n'est probablement pas en mesure de convertir la userIds.Contains parce qu'il est incapable de traduire cette liste en quelque chose qu'il peut exécuter sur une base de données SQL. Vous devrez probablement recourir à la définition explicite d'une condition or :

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

0voto

Adam Cooper Points 4319

Je suis presque sûr que cela fonctionnera si vous utilisez un IEnumerable au lieu d'une List. Ce qui suit devrait donc fonctionner :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X