Запрос анонимного объекта EF возвращает пустые коллекции вместо пустых

Я использую этот трюк для выполнения условных включений с EF. http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx

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

Например, коллекция StudentModules будет нулевой. Как я могу превратить его в пустой список в моем запросе? т.е. без необходимости перебирать все это и проверять.

Я могу поместить конструктор в poco для инициализации списка, который исправляет его, но эта коллекция является виртуальным членом в poco (на основе видео EF!) - конечно, это не тот путь?

var query = from module in db.Modules
            where module.Id == id
            select new 
            {
              module,
              QualificationModules = from qualificationModule in module.QualificationModules
                                     where qualificationModule.IsDeleted == false
                                     select new
                                     {
                                       qualificationModule,
                                       qualificationModule.Qualification,
                                       StudentModules = from studentModule in qualificationModule.StudentModules
                                                        where studentModule.IsDeleted == false 
                                                        select new
                                                        {
                                                          studentModule,
                                                          studentModule.Student
                                                        }
                                     },

              Assessments = (from assessment in module.Assessments
                             where assessment.IsDeleted == false
                             select new
                             {
                               assessment,
                               assessment.AssessmentType
                             }
                            )
            };

var modules = query.AsEnumerable().Select(x => x.module);

return modules.ToList().First();

1 ответ

Решение

Исправление отношений запускается, когда объект присоединяется к контексту - либо вручную, вызывая Attach или когда сущность материализуется в результате запроса (ваш случай).

Он основан на внешних ключах сущности и работает в обоих направлениях:

  • Если контекст уже содержит сущность A с внешним ключом f к сущности B и сущность B привязывается к контексту, который имеет первичный ключ с тем же значением f как внешний ключ в A (то есть эти два объекта связаны отношением FK), тогда Entity Framework сделает следующее:

    • Если A имеет свойство ссылки навигации для B это назначит прикрепленный объект B к этой собственности.
    • Если B имеет свойство ссылки навигации для A (отношение один-к-одному) A к этой собственности.
    • Если B имеет свойство коллекции навигации для A (отношение один ко многим) это добавит A к этой коллекции в прикрепленном объекте B, Если коллекция null он будет создавать экземпляр коллекции перед добавлением.
  • Если субъект B привязывается к контексту, который имеет внешний ключ f к сущности A что контекст уже содержит и имеет f в качестве первичного ключа EF установит свойства навигации на основе тех же правил, что и выше.

Примечание: тот факт, что исправление отношений основано на внешних ключах (они всегда загружаются при запросе объекта, независимо от того, отображается ли FK как свойство в классе модели или нет), также является причиной того, что исправление отношений делает не применяется и не работает для отношений "многие ко многим", потому что два объекта отношения "многие ко многим" не имеют внешнего ключа.

Теперь, если нет связанных StudentModules в вашем случае нет StudentModule объект, который загружается в контекст, и нет ничего, что EF мог бы предназначить для исправления. Имейте в виду, что алгоритм исправления не связан с конкретным запросом и не только фиксирует отношения между сущностями, которые этот запрос материализует, но и учитывает все сущности для исправления, которые контекст уже содержит, независимо от того, как они попали в контекст. Если вы хотите, чтобы экземпляры коллекций создавались как пустые коллекции, EF прошел через все присоединенные родительские объекты StudentModules и просто создать пустую коллекцию. Нет смысла делать это во время исправления вместо того, чтобы создавать пустые коллекции заранее, до того, как сущности присоединятся к контексту.

Я могу поместить конструктор в poco для инициализации списка, который исправляет его, но эта коллекция является виртуальным членом в poco (на основе видео EF!) - конечно, это не тот путь?

На мой взгляд, это лучшее решение, если вы не хотите иметь null коллекции в экземплярах вашего модельного класса. Неважно, если коллекция объявлена ​​как virtual (включить отложенную загрузку) или нет. Тип коллекции не имеет производного типа прокси, только экземпляры, добавленные в коллекцию, являются производными прокси. В обоих случаях вы можете просто использовать StudentModules = new HashSet<StudentModule>(); (или же List Если вы предпочитаете).

Другие вопросы по тегам