Особенности LINQ to SQL

Я встречаюсь с некоторыми особенностями LINQ to SQL.

С относительно простым запросом я хочу выбрать некоторые поля, но поля даты будут отформатированы как строки, которые я впервые получил следующим образом:

        var list = dataContext.MyLists.Single(x => x.ID == myId);

        var items = from i in list.MyItems
                    select
                        new
                            {
                                i.ID,
                                i.Sector,
                                i.Description,
                                CompleteDate = i.CompleteDate.HasValue ? i.CompleteDate.Value.ToShortDateString() : "",
                                DueDate = i.DueDate.HasValue ? i.DueDate.Value.ToShortDateString() : ""
                            };                               

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

        var items = from i in dataContext.MyLists
                    select
                        new
                            {
                                i.ID,
                                i.Sector,
                                i.Description,
                                CompleteDate = i.CompleteDate.HasValue ? i.CompleteDate.Value.ToShortDateString() : "",
                                DueDate = i.DueDate.HasValue ? i.DueDate.Value.ToShortDateString() : ""
                            };

Первый работает отлично, но второй запрос дает:

Невозможно перевести выражение "..." в SQL и не может рассматривать его как локальное выражение.

Если я удалю строки, которые форматируют дату, она отлично работает. Если я удалю проверку .HasValue, он также будет работать нормально, пока не будет нулевых значений.

Любые идеи?

Энтони

Ответ 1

Я бы сделал часть SQL без форматирования, а затем сделаю форматирование на стороне клиента:

var items = list.MyItems.Select(item => new { item.ID, item.Sector, item.Description, 
                                              item.CompleteDate, item.DueDate })
                        .AsEnumerable() // Don't do the next bit in the DB
                        .Select(item => new { item.ID, item.Sector, item.Description,
                                              CompleteDate = FormatDate(CompleteDate),
                                              DueDate = FormatDate(DueDate) });


static string FormatDate(DateTime? date)
{
    return date.HasValue ? date.Value.ToShortDateString() : ""
}

Ответ 2

В первом запросе вы уже получили данные из базы данных к моменту выполнения второй строки (var items =...). Это означает, что вторая строка выполняется на клиенте, где ToShortDateString может работать довольно счастливо.

Во втором запросе, поскольку выбор выполняется непосредственно в коллекции IQueryable (dataContext.MyLists), он пытается перевести выбор в SQL для обработки на сервере, где ToShortDateString не понят - следовательно, "Не удалось перевести".. "исключение.

Чтобы понять это немного лучше, вам действительно нужно понять разницу между IQueryable и IEnumerable, и в этот момент запрос Linq To Sql перестает быть IQueryable и становится IEnumerable. В Интернете есть много материала.

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

Пол

Ответ 3

Как и сообщение об ошибке, различие связано с тем, что можно удаленно удалять локальными стилями при подключении к SQL.

Код Linq должен быть преобразован Linq в SQL в команду SQL для удаленных данных - все, что нужно сделать локально, не может быть включено.

Как только вы поместили его в локальный объект (в первом примере), он больше не использует Linq to SQL, а просто Linq. В этот момент вы можете делать локальные манипуляции на нем.

Ответ 4

Возможно, в вашем примере была ошибка копирования и вставки или просто опечатка. Но если нет, это может быть проблемой...

Во втором запросе вы запрашиваете коллекцию списков, тогда как в первом запросе вы запрашивали элементы в списке. Но вы не скорректировали запрос для учета этой разницы.

Вам может понадобиться. Обратите внимание на прокомментированные строки, которые не отображаются во втором примере.

    var items = from aList in dataContext.MyLists
                from i in aList.MyItems  // Access the items in a list
                where aList.ID == myId  // Use only the single desired list
                select
                    new
                        {
                            i.ID,
                            i.Sector,
                            i.Description,
                            CompleteDate = i.CompleteDate.HasValue ? i.CompleteDate.Value.ToShortDateString() : "",
                            DueDate = i.DueDate.HasValue ? i.DueDate.Value.ToShortDateString() : ""
                        };