2014-02-06 5 views
1

Я следующий кодОшибка Linq к Entities Datetime

var dates = query.Select(
       x => DateTime.ParseExact(x.Date, "yyyy-MM", CultureInfo.InvariantCulture)); 

var minDate = dates.Min(x => x); 

Но когда я исполняю, я получаю исключение

System.Data.Entity.dll но не был обработан в пользовательском коде

Дополнительная информация: LINQ к Entities не распознает метод метод 'System.DateTime ParseExact (System.String, System.String, System.IFormatProvider)', и этот метод не могут быть переведены в выражение хранилища.

Что я делаю неправильно? И как я могу это исправить?

+0

Почему вы храните значения datetime как строку в db? Было бы намного проще, если бы вы использовали подходящие типы для своих значений. – MarcinJuraszek

+0

@MarcinJuraszek фактически db содержит значения формата «yyyy-MM», но у меня нет административного доступа к этому db –

+0

@MarcinJuraszek Спасибо за ваше редактирование и ваш интерес :) –

ответ

2

Ну, ошибка на самом деле совершенно ясна. В Linq нет перевода в Entities из ParseExact в SQL.

Помните, что Entity Framework под обложками преобразует запрос в команду SQL или набор команд. Если EF не знает, как что-то перевести, он выдает эту ошибку.

Одним из возможных решений, хотя и не очень эффективным, является преобразование IQueryable в IEnumerable, что позволит вам выполнить инструкцию.

var dates = query.ToList().Select(
      x => DateTime.ParseExact(x.Date, "yyyy-MM", CultureInfo.InvariantCulture)); 
+1

'query.ToList()' будет извлекать все данные из БД, а не только значение «x.Date», что важно. – MarcinJuraszek

+1

@MarcinJuraszek. Не зная схемы, вы не можете предположить, что в таблице содержится не более одного столбца. Я даю ответчику кредит за знание собственной схемы и внесение соответствующих изменений. –

+0

Да, я знаю, что это возможно. И именно поэтому я просто прокомментировал вместо downvoting :) – MarcinJuraszek

1

Боюсь, вам придется загрузить все ваши string представления datatime значений из БД в память:

var dates = query.Select(x => x.Date).ToList(); 

и выполнять синтаксический анализ и мин, как LINQ к объектам запроса:

var min = query.Min(x => DateTime.ParseExact(x, "yyyy-MM", CultureInfo.InvariantCulture)); 

Если ваш DB был установлен свойство и x.Date был DateTime вы могли бы сделать:

var dates = query.Select(x => x.Date); 
var min = dates.Min(); 

, который будет переведен в правильный SQL-запрос, и пусть MIN() будет вычисляться по базе данных, поэтому вам не придется извлекать все данные в память приложения.

+0

Большое спасибо Марцин. Я попробую это сейчас –

+0

ToList будет работать, и в этом нет ничего плохого, но если вы на самом деле не собираетесь использовать его в качестве списка, то зачем создавать список? Массивы более эффективны, чем списки, поэтому вы должны вызывать ToArray по умолчанию и только вызывать ToList, когда вам нужно. – jmcilhinney

+0

@jmcilhinney Я не вижу причин, почему «ToArray» был бы более эффективен здесь. Может быть, только факт, что 'ToArray()' будет сокращать выделенный массив, когда все записи будут загружены, когда 'ToList()' сохранит это неиспользуемое пространство в базовом массиве, чтобы в будущем сделать дополнительные вставки быстрее. – MarcinJuraszek

0

LINQ to Entities принимает ваш запрос LINQ и преобразует его в код SQL, который затем выполняет против базы данных. Это означает, что код, который вы пишете, должен быть преобразован в код SQL. Невозможно преобразовать DateTime.ParseExact в код SQL, следовательно, исключение. Вам нужно будет оценить запрос LINQ to Entities, вызывая ToArray, а затем вы можете выполнить второй запрос LINQ to Objects, и он будет понимать DateTime.ParseExact.

+0

Большое спасибо jmcilhinney за ответ. Тем не менее, я думаю, что ваш ответ может быть лучше поддержан, если бы он включал кусок кода :) –

2

Если даты в БД в виде строки в формате «YYYY-MM», то вы можете сделать запрос на основе строки сортировки и преобразовать результат в DateTime:

var minDateString = query.Select(x => x.Date).Min(); 
var minDate = DateTime.ParseExact(
    minDateString, 
    "yyyy-MM", 
    CultureInfo.InvariantCulture 
); 

Многие системы полагались на естественный порядок строк «yyyy-MM-dd hh: mm: ss», вы можете так же легко полагаться на подмножество этого упорядочения.

+0

Большое спасибо Тимоти. Приобретено за вашу помощь :) –

+0

@JimBlum из комментариев, которые вы сделали по другим ответам, похоже, вы хотите сделать больше, чем просто получить минимальную дату. Не могли бы вы обновить свой вопрос более подробно о том, что вам нужно, чтобы я мог дать лучший ответ? Я часто прибегаю к двухэтапному процессу, сокращаю свои строки и получаю столько необработанных данных, сколько мне нужно, а затем в '.ToList()', тогда я благополучно использую все вызовы, не совместимые с SQL, которые мне нравятся на встроенной памяти , –

Смежные вопросы