Linq создает исключение для .Substring () - PullRequest
2 голосов
/ 14 декабря 2010

У меня есть ситуация, когда мне нужно, чтобы мой запрос LINQ to Entities возвращал подстроку в зависимости от длины строки.Вот запрос:

var query = (
    from f in Context.Files
    orderby f.DateAdded descending
    select new
    {
        Concerns = f.Concerns.Name,
        Sender = f.Sender.Name,
        CategoryCount = f.Categories.Count(),
        DateAdded = f.DateAdded,
        Comment = (f.Comment == null || f.Comment.Length < 5) 
            ? f.Comment : f.Comment
    }).Take(10);

Итак, я получаю последние 10 добавленных сущностей типа Files, а затем выбираю из них набор свойств для отображения внутри списка.Некоторые из них - простые строки (Концерны, Отправитель).CategoryCount возвращает количество категорий, связанных с объектом File.

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

Comment = (f.Comment == null || f.Comment.Length < 5) 
    ? f.Comment : f.Comment

На эту строку:

Comment = (f.Comment == null || f.Comment.Length < 5) 
    ? f.Comment : f.Comment.SubString(0,5)

приложение выдает исключение XamlParseException (???)

Вызовконструктора типа «DocumentManager.Views.ListEntriesView», который соответствует указанным ограничениям связывания, вызвала исключение

Я действительно не знаю, почему он это сделал.Метод SubString не поддерживается в LINQ?

Надеюсь, что кто-то может мне помочь.А пока я просто оставлю все как есть.

РЕДАКТИРОВАТЬ 2 (почему-то мое первое редактирование потеряно. Поэтому я его переделываю): основываясь на полученных комментариях, я изменил свой код наэто и сейчас работает:

var query = App.Context.Files.OrderByDescending(File => File.DateAdded).Take(10).AsEnumerable()
            .Select(File => new
            {
                Concerns = File.Concerns.Name,
                Sender = File.Sender.Name,
                CategoryCount = File.Categories.Count(),
                DateAdded = File.DateAdded,
                Comment = (File.Comment == null || File.Comment.Length < 100) ? File.Comment : File.Comment.Substring(0, 100) + "..."
            });

Я забыл упомянуть, что я использую SQLite.Так что, возможно, Substring не реализована в провайдере SQLite EF.

Ответы [ 4 ]

3 голосов
/ 14 декабря 2010

Это не вина LINQ на самом деле. Ваша модель привязана к IQueryable, то есть подпрограммам, напрямую поддерживаемым вашей базой данных (все остальное выдает исключения). Вы должны использовать метод AsEnumerable в какой-то момент, чтобы сделать все остальное.

Подробнее о том, как Билл Вагнер объясняет разницу между IQueryable и IEnumerable, можно узнать здесь:

http://msdn.microsoft.com/en-us/vcsharp/ff963710

2 голосов
/ 14 декабря 2010

Не знаю точно, но я подозреваю, что подстрока не поддерживается Linq-to-Entities.Я бы переместил ваш Take (10) до вашего оператора select, затем после Take (10) вызову AsEnumerable (), а затем ваш оператор select после этого.Это заставит вас извлечь коллекцию файлов из базы данных, после чего проекция будет выполнена в памяти.

1 голос
/ 30 мая 2015

Это похоже на ошибку в синтаксическом анализаторе SQLite, потому что

  • Подстрока работает правильно для запроса в базу данных SQL Server с LINQ to Entities

  • Если вы посмотрите в сгенерированном журнале SQL, он генерирует его как функцию подстроки SQL

  • В SQLite правильная функция - substr, а не подстрока

Таким образом, в способе создания запроса есть ошибка.

Вот способ исправить эту ошибку.

В вашей модели базы данных добавьте этот код прямо перед EntityContainer

<Function Name="substr" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" ReturnType="nvarchar">
  <Parameter Name="text" Type="nvarchar" Mode="In" />
  <Parameter Name="startPos" Type="int" Mode="In" />
</Function>

В своем классе контекста (создайте частичный класс рядом с ним) добавьте этот код

[DbFunction("MyModel.Store", "substr")]
public string SubStr(string text, int startPos) {
    return text.Substring(startPos);
}

В своем коде вызовите Substring следующим образом

context.SubStr(text, startpos)

Теперь он будет корректно отображаться в функции SUBSTR вместо SUBSTRING!Это похоже на сопоставление пользовательской функции, за исключением того, что мы сопоставляем существующую стандартную функцию.

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

0 голосов
/ 14 декабря 2010

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

...