У метода 'Boolean Contains ..' нет поддерживаемого перевода в SQL - PullRequest
1 голос
/ 18 июля 2010

У меня есть это в моем запросе:

var results = (from urls in _context.Urls
               join documents in _context.Documents on urls.UrlId equals documents.DocumentId
               let words = (from words in _context.Words
                            join hits in _context.Hits on words.WordId equals hits.WordId
                            where hits.DocumentId == documents.DocumentId
                            select words.Text).AsEnumerable<string>()

                where urls.ResolvedPath.Contains(breakedQuery, KeywordParts.Url, part) ||
                      documents.Title.Contains(breakedQuery, KeywordParts.Title, part) ||
                      documents.Keywords.Contains(breakedQuery, KeywordParts.Keywords, part) ||
                      documents.Description.Contains(breakedQuery, KeywordParts.Description, part) ||
                      words.Contains(breakedQuery, KeywordParts.Content, part) ...

и содержит метод расширения:

для струнных

public static bool Contains(this string source, IEnumerable<string> values, KeywordParts valuePart, KeywordParts part)
    {
        if (!string.IsNullOrWhiteSpace(source))
            return source.Split(' ').AsEnumerable<string>().Contains(values, valuePart, part);
        return false;
    }

для счетчиков (основной метод)

public static bool Contains(this IEnumerable<string> source, IEnumerable<string> values, KeywordParts valuePart, KeywordParts part)
    {
        if (source != null && source.Count() > 0 &&
            values != null && values.Count() > 0 &&
            (part == KeywordParts.Anywhere || valuePart == part))
        {
            foreach (var value in values)
            {
                var has = false;
                var none = (value.StartsWith("-"));
                string term = value.Replace("-", "");

                if (none)
                    has = source.Any(q => !q.Contains(value));
                else
                    has = source.Any(q => q.Contains(values));

                if (has)
                    return has;
            }
        }
        return false;
    }

и использование метода Contains выдает исключение NotSupportedException: метод 'Boolean Contains (String, IEnumerable`1 [String], KeywordParts, KeywordParts)' не поддерживает перевод в SQL.

на самом деле я хочу проверить каждый проиндексированный документ, если у него есть в аренде одно из указанных условий

Ответы [ 5 ]

3 голосов
/ 18 июля 2010

Мое понимание, и кто-то, пожалуйста, исправьте меня, если я ошибаюсь, проблема в том, что при использовании метода расширения с Linq to SQL метод расширения не выполняется как код .NET, как методы расширения, которые у вас есть в вашем вопросе.

Методы расширения Linq to SQL возвращают деревья выражений , которые затем анализирует механизм Linq to SQL и генерирует соответствующий запрос SQL для удовлетворения дерева выражений.

3 голосов
/ 18 июля 2010

Другим способом реализации этого является запись в базу данных скалярного UDF, который реализует эту функциональность. Затем перетащите этот UDF в конструктор LINQ-to-SQL, который даст вам доступ к вашему UDF через контекст данных. Тогда вы можете использовать такие вещи, как:

where _context.MyContains(documents.Title, breakedQuery,
       KeywordParts.Title, part);

и который будет вызывать UDF после перевода (т.е. WHERE dbo.MyContains(...))

3 голосов
/ 18 июля 2010

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

Вы можете принудительно выполнить предложение where в .NET после извлечения документов и слов, потенциально ... хотя, очевидно, это означает получение всех объединенных данных из базы данных. Это будет хорошо?

Для этого вам нужно что-то вроде:

var tmpQuery = (from urls in _context.Urls
                join documents in _context.Documents 
                on urls.UrlId equals documents.DocumentId
                let words = (from words in _context.Words
                             join hits in _context.Hits 
                             on words.WordId equals hits.WordId
                             where hits.DocumentId == documents.DocumentId
                             select words.Text)
                select new { urls, documents, words };

var query = from r in tmpQuery.AsEnumerable()
            let urls = r.urls.ToList()
            let words = r.words.ToList()
            let documents = r.documents.ToList()
            where urls.ResolvedPath.Contains(breakedQuery, 
                                             KeywordParts.Url, part) ||
               documents.Title.Contains(breakedQuery,
                                        KeywordParts.Title, part) ||
               documents.Keywords.Contains(breakedQuery,
                                           KeywordParts.Keywords, part) || 
               documents.Description.Contains(breakedQuery, 
                                              KeywordParts.Description, part) ||
               words.Contains(breakedQuery, KeywordParts.Content, part)
            select new { urls, words, documents };
1 голос
/ 19 апреля 2011

Интересным фактом является то, что я получаю следующую ошибку при запуске в .NET 4.0 на моей машине разработки:

"Метод 'Boolean Contains (Int32)' не поддерживает перевод на SQL."

Но он отлично работает в производственной среде, использующей .NET 3.5.

Я предполагаю, что это разница в версиях между двумя средами.Тем не менее, это факт, что я получаю ошибку на моей машине разработки, но запросы DO RUN запускаются в производственной среде, и запрос LINQ действительно содержит следующий код

var resultParts = (
                from l in tempDc.LineItems
                from wo in tempDc.WorkOrders
                where l.WorkOrderNumber == wo.WorkOrderNumber &&
                    l.OrderID == wo.OrderID &&
                    workOrderSerialNumbers.Contains(wo.SerialNumber) &&
                    l.Part.PartTypeID == (int)PartTypes.InventoryPart
                orderby l.OrderID_WO, l.WorkOrderNumber
                select new PickReportPartDto()
                {...

Где 'workOrderSerialNumbers - это список.

0 голосов
/ 04 сентября 2014

Это возможно, если вы возьмете свой перечислитель и добавите к .ToList () до .Contains (r.SomeId). Я искал эту ошибку и первоначально имел ICollection с .Contains (r.SomeId), который выдает это исключение, однако выполнение .ToList () решило мою проблему. Надеюсь, это поможет кому-то еще.

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

Это код Linq2Sql:

enter image description here

Это результирующий SQL: enter image description here

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