Linq - Использование запроса в качестве функции в выборе - PullRequest
0 голосов
/ 15 февраля 2019

Когда я вызываю функцию в выборе, я получаю эту ошибку: вторая операция началась в этом контексте до завершения предыдущей операции.

public bool func2(int ID)
    {
        return (from t2 in _odc.table2
                where t2.ID == ID &&
                (t2.col1 > 0 ||
                t2.col2 != "" ||
                t2.col3 != "")
                select t2
               ).Any();
    }

public List<MyModel> func1()
    {

        return (from t1 in _odc.t1
                join t3 in _odc.t3 on t1.ID equals t3.ID
                where t1.col2 > 300
                where t1.col3 != 1
                where t1.col4 != 285
                where t1.col5 != 830
                where t1.col6 > 0
         select new MyModel
                {
                    ID = t1.ID,
                    isFunc2 = func2(t1.ID),
                }).ToList();
    }

Могу ли я сделать это так или ядолжен вызывать func2 в функции foreach?(Уже проверил, и он работает с foreach).

1 Ответ

0 голосов
/ 21 февраля 2019

Вы должны понимать, что ваш запрос реализует IQueryable<...>.

Объект, который реализует IQueryable, имеет Expression и Provider.Expression является общим представлением того, что должно быть запрошено.Provider знает, кто должен выполнить запрос и на каком языке использует этот исполнитель.

Когда вы начинаете перечислять последовательность, которую представляет IQueryable (= при вызове .ToList()), Expressionотправлено на Provider.Provider переведет Expression на язык, который понимает процесс, который должен выполнить запрос (обычно SQL), и отправит его исполняющему процессу.

Возвращенные данные помещаются в объект, который реализуетIEnumerable<...>, и этот объект перечисляется.

Проблема в том, что поставщик знает только, как перевести довольно простой Expressions в SQL.Он не знает, как перевести Func2.

Я не вижу, чтобы вы использовали какой-либо элемент T3 в своем запросе.Это ошибка ввода?

В любом случае, самым простым решением было бы поместить код Func2 в Func1:

(я больше знаком с синтаксисом метода LINQ, чем с LINQ).синтаксис запроса, но вы получите суть)

см. Enumerable.Join

var result = dbContext.T1
    // don't take all T1 items, but only the ones where:
    .Where(t1 => t1.col2 > 300
              && t1.col3 != 1
              && t1.col4 != 285
              && t1.col5 != 830
              && t1.col6 > 0
    // join the remaining t1s with table T3
    .Join dbContext.T3,
          t1 => t1.Id,               // from every T1 take the id
          t3 => t3.Id,               // from every T3 take the id

          // ResultSelector: take a t1 and a matching t3 to create one new object
          (t1, t3) => new MyModel
          {
              Id = t1.Id,

              // IsFunc2: true if Table2 has any element with Id equal to t1.Id and col values
              IsFunc2 = dbContext.Table2
                        .Where(t2 => t2.ID == t1.Id
                                  && (t2.col1 > 0 || t2.col2 != "" || t2.col3 != ""))
                        .Any();
    });

Если вы будете часто использовать Func2 в различных выражениях, вы можетерассмотрим преобразование Func2 таким образом, чтобы оно принимало IQueryable в качестве входных данных.

Я создал его как функцию расширения IQueryable<Table2Row>.См. Расширение методов расширения:

static bool Func2(this IQueryable<Table2Row> rows, int id)
{
    return rows
        .Where(row => row.ID == id && (row.col1 > 0 || row.col2 != "" || row.col3 != ""))
        .Any();
}

Теперь вы можете использовать его в ResultSelector соединения:

(t1, t3) => new MyModel
{
    Id = t1.Id,
    IsFunc2 = dbContext.Table2.Func2(t1.Id),
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...