MVC LINQ Нераспознанный метод

У меня есть запрос linq, извлекающий данные из таблицы, и я хочу, получив дату, преобразовать ее в неделю (например, какая неделя года).

И функция GetWeekofYear:

 private int GetWeekOfYear(DateTime d)
 {
     var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
     return cal.GetWeekOfYear(new DateTime(d.Year, d.Month, 1), System.Globalization.CalendarWeekRule.FirstDay, System.DayOfWeek.Sunday);
 }

В его текущем состоянии, когда я пытаюсь его протестировать (используя Postman/Fiddler), я получаю следующую ошибку:

LINQ to Entities не распознает метод Int32 GetWeekOfYear(System.DateTime) и этот метод нельзя преобразовать в выражение хранилища.


person Random User    schedule 12.08.2016    source источник
comment
Сначала вам нужно материализовать свой запрос в память - var query = (from booking ..... where .... ).ToList().Select(x => new QuestionaireDetailsDTO() { .... });   -  person    schedule 12.08.2016
comment
Я решил это, установив геттер в объект, но у меня есть другой вопрос. Как я могу предотвратить сериализацию в json для некоторого свойства объекта и сериализовать его, только если захочу? Я пробовал [IgnoreDataMember], но, похоже, это не так, как хотелось бы. @СтивенМюке   -  person Random User    schedule 12.08.2016
comment
Вам нужно задать новый вопрос с соответствующими деталями.   -  person    schedule 12.08.2016


Ответы (3)


Ошибка возникает из-за того, что Linq2Sql не может преобразовать метод GetWeekOfYear в SQL.

Попробуйте следующее:

  • вместо этого выберите необработанные данные в QuestionaireDetailsDTO

    select new QuestionaireDetailsDTO() {
        DepartureDate = transport.DepartureDate 
    };
    
  • добавьте геттер к QuestionaireDetailsDTO, который выполняет расчет:

    public string Week => GetWeekOfYear(DepartureDate);
    

Таким образом, преобразование происходит в памяти, а не в БД.

Если метод GetWeekOfYear находится в проекте, который недоступен потребителю DTO, вместо этого добавьте шаг постобработки после того, как вы выбрали DTO из базы данных.

foreach (var result in query) {
     result.Week = GetWeekOfYear(result.DepartureDate);
}
person Georg Patscheider    schedule 12.08.2016

Вы можете сделать это, используя .AsEnumerable()

var query = from booking in context.BookingTables
                    join transport in context.TransportAllotments on booking.TransportAllotmentID equals transport.TransportAllotmentID
                    join passenger in context.Passengers on booking.BookingID equals passenger.BookingID
                    join result in context.QuestionaireResults on passenger.PassengerID equals result.PassengerID
                    join question in context.QuestionaireQuestions on result.QuestionaireQuestionID equals question.QuestionaireQuestionID
                    where transport.DepartureDate >= startDate && transport.DepartureDate <= endDate && booking.BookingID == id
                    .AsEnumerable()
                    select new QuestionaireDetailsDTO()
                    {
                        ID = booking.BookingID,
                        Date = transport.DepartureDate,
                        Question = question.QuestionText,
                        Week =  GetWeekOfYear(transport.DepartureDate) 

                    };

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

person Phong Dao    schedule 12.08.2016

Как я уже говорил, это происходит потому, что LinqToSQL не смог преобразовать ваш метод в SQL. Я думаю, что ответ @GeorgPatscheider не лучший, потому что вы не должны изменять свои объекты данных из-за некоторых специфических механизмов уровня доступа к данным. Итак, ответ от @PhongDao более крутой, но его решение загрузит слишком много полей из базы данных. Вы можете изменить свой код следующим образом:

var query = from booking in context.BookingTables
        join transport in context.TransportAllotments on booking.TransportAllotmentID equals transport.TransportAllotmentID
        join passenger in context.Passengers on booking.BookingID equals passenger.BookingID
        join result in context.QuestionaireResults on passenger.PassengerID equals result.PassengerID
        join question in context.QuestionaireQuestions on result.QuestionaireQuestionID equals question.QuestionaireQuestionID
        where transport.DepartureDate >= startDate && transport.DepartureDate <= endDate && booking.BookingID == id
        // select only fields which we need
        select new
            {
                ID = booking.BookingID,
                Date = transport.DepartureDate,
                Question = question.QuestionText,
                DepartureDate = transport.DepartureDate
            }
        // retrieve data from DB
        .ToArray()
        // create items which you need
        .Select(x=>
        new QuestionaireDetailsDTO()
        {
            ID = x.ID,
            Date = x.Date,
            Question = x.Question,
            Week = GetWeekOfYear(x.DepartureDate)
        })
        // forming results
        .ToArray();
person tym32167    schedule 12.08.2016
comment
Я решил это, установив геттер в объект, но у меня есть другой вопрос. Как я могу предотвратить сериализацию в json для некоторого свойства объекта и сериализовать его, только если захочу? Я пробовал [IgnoreDataMember], но, похоже, это не так, как хотелось бы. - person Random User; 12.08.2016
comment
Я думаю, что это должен быть отдельный вопрос. - person tym32167; 12.08.2016