Лямбда содержится в SimpleRepository.Find - PullRequest
2 голосов
/ 20 мая 2010

В SimpleRepository SubSonic 3.04 я не могу выполнить операцию Contains в лямбда-выражении. Вот тривиальный пример:

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

Я получаю сообщение об ошибке:

переменная 'x' типа 'Пользователь', на которую ссылается область действия '', но она не определена

Я что-то здесь упускаю или SubSonic не поддерживает Contains в лямбда-выражениях? Если нет, как бы это сделать?

Ответы [ 3 ]

4 голосов
/ 20 мая 2010

Так как ни один из них, кажется, не работает ...

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

... мы пишем пользовательский конструктор лямбда-выражений, который генерирует:

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

Это тривиальный сценарий, но он демонстрирует, как GetContainsId<User>(ids, repo) найдет всех пользователей с идентификатором, совпадающим с указанным в списке.

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));
}
0 голосов
/ 20 мая 2010

Я почти уверен, что это будет работать, если вы используете IEnumerable вместо List. Поэтому должно работать следующее:

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();
0 голосов
/ 20 мая 2010

Вероятно, Subsonic не может преобразовать userIds.Contains, потому что он не может преобразовать этот список во что-то, что он может выполнить в базе данных SQL.Вам, вероятно, придется прибегнуть к точному определению условия или:

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