Linq2Sql -> Поиск в базе данных по локальной коллекции значений - «Запросы с локальными коллекциями не поддерживаются» - PullRequest
2 голосов
/ 06 августа 2009

Я бегу к стене с Linq2SQL. Я люблю это, его удивительная гибкость, но я столкнулся с интересными зависаниями. Я надеюсь, что это просто мое отсутствие знаний об этом, и действительно есть решение. Возьмем для примера ... запрос linq2sql, подобный этому:

// некоторая локальная коллекция идентификаторов

var terminalID = new List<int>(){1, 2, 3, 4, 5};

// часть оператора Linq:

queryDataIDs.Where(q => q.DataEventKeyID == 2 && terminalID.Contains((int)q.ValueDecimal));

приведет к ошибке @ runtime

"NotSupportedException was unhandled"
"Queries with local collections are not supported"

Stack:

at System.Data.Linq.SqlClient.SqlBinder.Visitor.ConvertToFetchedSequence(SqlNode node)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
   at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
   at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
   at System.Data.Linq.SqlClient.SqlVisitor.VisitSequence(SqlSelect sel)
   at System.Data.Linq.SqlClient.SqlVisitor.VisitExists(SqlSubSelect sqlExpr)
   at System.Data.Linq.SqlClient.SqlVisitor.VisitSubSelect(SqlSubSelect ss)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSubSelect(SqlSubSelect ss)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitBinaryOperator(SqlBinary bo)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
   at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)

Что я делаю не так? Google / Bing не сообщит о многих решениях этого, но это кажется прямым.

Это не решение - оно не работает. Та же ошибка.

Работа вокруг LinqToSQls «запросы с локальными коллекциями не поддерживаются» исключение

Ответы [ 4 ]

1 голос
/ 08 августа 2009

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

where queryDataIDs.Select(x => x.ID).Contains(dataEvent.DataEventID)

Но это будет ошибкой. Я пытался заставить его выполнить подзапрос в моем операторе where по запросу №2.

ЕСЛИ я делаю это так:

where queryDataIDs.ToList().Select(x => x.ID).Contains(dataEvent.DataEventID)

Нет проблем. Но проблема в том, что он превращает один запрос в два запроса (на уровне сервера sql). Производительность хорошая, потому что она обрабатывается в одном соединении, но я надеялся получить хороший отдельный запрос для выполнения.

Итак, я прошу прощения за размещение неправильной части кода. Кажется, что Linq2Sql не может создать подзапрос, как я пытался сделать, но это незначительная неудача.

0 голосов
/ 06 августа 2009

Edit: похоже, что вы пытаетесь запросить queryDataIDs, что это? Вы хотите запросить DataContextInstance.LinqToSqlCollection

var myResults = (
     from q in DataContextInstance.LinqToSqlCollection
     where q.DataEventKey == 2 && terminalID.Contains((int)q.ValueDecimal) 
     select q);

или, если вы просто хотите идентификаторы, измените его на q.DataEventKey вместо q

0 голосов
/ 08 августа 2009

Ваша проблема в том, что вы пытаетесь выполнить SQL-запрос, включая «динамические» локальные переменные. Дело в том, что linq2sql не может сделать такой запрос:

select * from table
where id in (--list of ids here referenced from a local variable--)

Сначала вы должны собрать свой Список из таблицы в вашей базе данных:

IQueryable<int> terminalID = db.terminals.where(p=>p.id<=5).select(x=>x.id);

затем продолжайте свой запрос:

queryDataIDs.Where(q => q.DataEventKeyID == 2 && terminalID.Contains((int)q.ValueDecimal));

Надеюсь, это поможет

0 голосов
/ 06 августа 2009

Я не мог воспроизвести вашу проблему. Однажды я пытался создать экземпляр объекта, чтобы выяснить, есть ли проблема с вашим синтаксисом Linq, но это сработало. Итак, я создал таблицу Sql: TestQueryData (DataEventKeyID: int (pk), ValueDecimal: десятичный (5,3))

Затем я создал dbml LinqToSql с этим классом / таблицей, и ваш код все еще дал результат. Я изменил логическое значение и другое выражение Where, и оно все еще работает в обеих ситуациях.

/* // This all works
             IQueryable<QueryData> queryDataIDs = new QueryData[]{ 
                new QueryData{DataEventKeyID = 1, ValueDecimal = 2.2m },
                new QueryData{DataEventKeyID = 2, ValueDecimal = 2.3m },
                new QueryData{DataEventKeyID = 3, ValueDecimal = 2.4m },
                new QueryData{DataEventKeyID = 4, ValueDecimal = 2.5m },
                new QueryData{DataEventKeyID = 5, ValueDecimal = 2.6m },
                new QueryData{DataEventKeyID = 6, ValueDecimal = 2.7m },
                new QueryData{DataEventKeyID = 7, ValueDecimal = 2.8m },
                new QueryData{DataEventKeyID = 8, ValueDecimal = 2.9m }
            }.AsQueryable();

            // some local collection of ids 
            var terminalID = new List<int>(){1, 2, 3, 4, 5};

            // a part of a Linq statement: 
            var selectedValues = queryDataIDs
                .Where(q => q.DataEventKeyID == 2)
                .Where(q => terminalID.Contains((int)q.ValueDecimal)); */

            TestQueryDataDataContext db = new TestQueryDataDataContext();
            IQueryable<TestQueryData> queryDataIDs = db.TestQueryDatas;
            var terminalID = new List<int>() { 1, 2, 3, 4, 5 };
            var selectedValues = queryDataIDs
                .Where(q => q.DataEventKeyID == 2)
                .Where(q => terminalID.Contains((int)q.ValueDecimal));

Я предполагаю, что ваш список - это общий список целых, потому что он не отображается в вашем сообщении. Кроме того, если ваша таблица базы данных допускает нулевые значения для ValueDecimal, вам придется проверить это, прежде чем пытаться привести к int.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...