LINQ "'s' находится вне области действия" при создании предложения where динамически - PullRequest
3 голосов
/ 15 декабря 2011

Итак, я получаю ошибку в названии.Я прыгну прямо в соответствующий код.Сначала ручное создание оператора where (который работает), а затем динамическое создание, которое не работает.Оба создают одно и то же выражение queryExpression.

Во-первых, выражение queryExpression, сгенерированное обоими методами:

{Table(Products).Select
  (s => new SalesData() {
    ProductID = s.ProductID,
    StoreName = s.StoreName, 
    Count = s.Count
}).Where(s => (s.Count > 500))}

Теперь ручной метод, который работает:

IQueryable<SalesData> data = ( from s in sales.Products
                               select new SalesData
                               {
                                   ProductID = s.ProductID,
                                   StoreName = s.StoreName,
                                   Count = s.Count
                               } ).AsQueryable<SalesData>();

data = data.Where(s => s.Count > 500);

this.dataGridView1.DataSource = null;

this.dataGridView1.DataSource = (from d in data
                                 select new
                                 {
                                     d.ProductID,
                                     d.StoreName,
                                     d.Count
                                 } );

Это работает как ожидалось;мой DataGridView заполнен данными.

Теперь, чтобы динамически создать предложение where:

IQueryable<SalesData> data = ( from s in sales.Products
                               select new SalesData
                               {
                                   ProductID = s.ProductID,
                                   StoreName = s.StoreName,
                                   Count = s.Count
                               } ).AsQueryable<SalesData>();

if (this.filter.Predicate != null)
{
    Expression<Func<SalesData, bool>> lambda =
        Expression.Lambda<Func<SalesData, bool>>(this.filter.Predicate,
            new ParameterExpression[] { this.filter.PE });

    data = data.Where(lambda);
}

this.dataGridView1.DataSource = null;

this.dataGridView1.DataSource = (from d in data  <---- fails here
                                 select new
                                 {
                                     d.ProductID,
                                     d.StoreName,
                                     d.Count
                                 } );

Единственное, что отличается, это то, что во втором фрагменте я создаю лямбдувыражение динамически.Я отметил, что во втором фрагменте происходит сбой.

Используя отладчик, я вижу queryExpression для данных, и он одинаков для обоих методов, поэтому я не думаю, что моя проблема связана с моим настоящим выражениемсоздание.Если этот код нужен, я могу опубликовать его здесь.

Мой вопрос: что я делаю неправильно и как я могу это исправить?

Редактировать: Вотфункция, которая дает фильтр. Предикат это значение:

public static Expression GetPredicate(List<FilterItem> itemList, ParameterExpression pe)
{
    List<Expression> expressions = new List<Expression>();
    List<string> combiners = new List<string>();

    foreach (FilterItem item in itemList)
    {
        Expression left = Expression.PropertyOrField(pe, item.Field);
        Expression right = Expression.Constant(Convert.ToInt32(item.Value), typeof(int));

        expressions.Add(Expression.GreaterThan(left, right));
        combiners.Add(item.Combiner);
    }

    int expressionCount = expressions.Count();
    Expression predicateBody = expressions[0];

    if (expressionCount > 1)
    {
        for (int x = 1; x <= expressionCount; x++)
        {
            switch (combiners[x - 1])
            {
                case "AND":
                    predicateBody = Expression.And(predicateBody, expressions[x]);
                    break;
                case "OR":
                    predicateBody = Expression.Or(predicateBody, expressions[x]);
                    break;
                default:
                    break;
            }
        }
    }

    return predicateBody;
}

Внутренний фильтр у меня есть:

this.Predicate = BuildPredicate.GetPredicate(this.filterList, this.PE);

this.PE это:

public ParameterExpression PE
{
    get
    {
        return Expression.Parameter(typeof(SalesData), "s");
    }
}

Ответы [ 2 ]

5 голосов
/ 15 декабря 2011

От отца C # Андерса Хейлсберга:

На параметры ссылаются в выражениях через идентичность их объектов, а не путем сравнения их имен.Фактически, с точки зрения дерева выражений, имя параметра является чисто информационным.Причиной такого дизайна является та же причина, по которой на типы ссылаются через их объекты System.Type, а не их имена - деревья выражений полностью связаны и не занимаются реализацией правил поиска имен (которые могут различаться в зависимости от языка).

Из форумов MSDN

Короче говоря, filter.Predicate имеет значение {(s.Count > 500)}, но это не значит, чтоs имеет здесь значение, разделяя имя с исходным выражением LINQ.

0 голосов
/ 20 декабря 2011

Мне удалось решить мою проблему благодаря диалоговому окну на этой странице и использованию Predicate Builder .

Лучший способ для того, что я пытаюсь сделать, можно найти на сайте Скотта Гу . Это лучше для моих целей, потому что мне нужно определить поле и значение динамически, а также разрешить группирование (проще с этим методом).

...