Форматирование даты в запросе Linq-to-Entities вызывает исключение - PullRequest
9 голосов
/ 30 апреля 2011

У меня есть класс Entity с полем datetime, я хочу выбрать отдельное значение поля datetime формата mon-yyyy и заполнить раскрывающийся список.

следующий код, выдающий мне ошибку:

var env = db.Envelopes.Select(d => new
        {
            d.ReportDate.Year,
            d.ReportDate.Month,
            FormattedDate = d.ReportDate.ToString("yyyy-MMM")
        }).Select(d => d.FormattedDate)

    List<SelectListItem> _months = new List<SelectListItem>();         

    foreach (var mname in env)
    {
        _months.Add(new SelectListItem() { Text = mname, Value = mname });
    }

Сообщение об ошибке:

LINQ to Entities не распознает метод метода System.String ToString (System.String), и этот метод нельзя преобразовать ввыражение магазина.

Как я могу исправить это сообщение об ошибке?

Спасибо SR

Ответы [ 4 ]

13 голосов
/ 30 апреля 2011

Помните, что ваш запрос будет переведен в SQL и отправлен в базу данных. Ваша попытка отформатировать дату не поддерживается в запросе, поэтому вы видите именно это сообщение об ошибке. Вам необходимо получить результаты и затем отформатировать их после того, как данные были материализованы.

Один из вариантов - просто выбрать дату как она есть. По мере итерации по результату форматируйте его, добавляя в список. Но вы также можете добиться построения списка с отформатированной датой в одном операторе, используя цепочку методов.

List<SelectListItem> _months = db.Envelopes.OrderByDescending(d => d.ReportDate)
        .Select(d => d.ReportDate)
        .AsEnumerable() // <-- this is the key method
        .Select(date => date.ToString("MMM-yyyy"))
        .Distinct()
        .Select(formattedDate => new SelectListItem { Text = formattedDate, Value = formattedDate })
        .ToList(); 

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

9 голосов
/ 03 мая 2013

Вот альтернатива:

.Select( p -> SqlFunctions.StringConvert((double)
                  SqlFunctions.DatePart("m", p.modified)).Trim() + "/" +
              // SqlFunctions.DateName("mm", p.modified) + "/" + MS ERROR?
              SqlFunctions.DateName("dd", p.modified) + "/" +
              SqlFunctions.DateName("yyyy", p.modified)

По-видимому, DateName("MM", ..) содержит название месяца, где DatePart("mm", ..) предоставляет числовое значение, то есть StringConvert( ), но в этом случае результат дополняется пробелами, поэтому .Trim().

Как сказал выше Энтони Пеграм, это происходит в базе данных, а не в C # (.AsEnumerable() извлекает все данные, локальные для C #, поэтому убедитесь, что вы фильтруете данные перед их использованием.)

Очевидно, что вы захотите немного изменить порядок вывода, чтобы он соответствовал yyyy-MM, и используйте либо DatePart для цифры, либо DateName для названия месяца.

1 голос
/ 26 июня 2014

Вот альтернатива, которая использует общий формат дд / мм / гггг. Подтверждено в SQL Server 2012 с Entity Framework 5

invoices.Select(i => new 
{
    FormattedDate = (     EntityFunctions.Right(String.Concat(" ", SqlFunctions.StringConvert((double?) SqlFunctions.DatePart("dd", i.DocumentDate))), 2)
                        + "/"
                        + EntityFunctions.Right(String.Concat(" ",SqlFunctions.StringConvert((double?) SqlFunctions.DatePart("mm", i.DocumentDate))), 2)
                        + "/"
                        + EntityFunctions.Right(SqlFunctions.StringConvert((double?) SqlFunctions.DatePart("yyyy", i.DocumentDate)), 4)
                       ).Replace(" ", "0")
}

Создает даты в формате дд / мм / гггг с ведущими нулями.

0 голосов
/ 23 августа 2016

Я использовал обходной путь для создания форматов, содержащих yyyy и MM вручную. Я хотел бы упомянуть об этом здесь, если это может кому-то помочь (хотя бы временно):

FormattedDate = d.ReportDate.Year.ToString() + "-" + d.ReportDate.Month.ToString()

это делает формат yyyy-MM

...