Question

Dans SubSonic 3.04 de SimpleRepository, je ne peux pas sembler effectuer une opération de 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();

Je reçois le message d'erreur:

  

variable 'x' de type 'utilisateur' référencé à partir de la portée '', mais il ne se définit pas

Suis-je manque quelque chose ici, ou ne prend pas en charge SubSonic Contains dans les expressions lambda? Sinon, comment peut-il être fait?

Était-ce utile?

La solution

Comme aucune de ces travaux semblent ...

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

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

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

Ceci est un scénario trivial, mais montre comment GetContainsId<User>(ids, repo) trouverez tous les utilisateurs avec un identifiant qui correspond à quelque chose dans 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));
}

Autres conseils

Subsonic est probablement pas en mesure de convertir le 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 aurez probablement à recourir à la définition explictely une ou condition:

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

Je suis assez sûr que cela fonctionnera si vous utilisez un IEnumerable au lieu d'une liste. Donc, ce qui suit devrait 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();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top