С#. Entity. Навигационные свойства и загрузка данных

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

Допустим, для каждого футболиста может быть определена футбольная команда, в которой он играет. И, наоборот, в одной футбольной команде могут играть несколько футболистов. То есть в данном случае у нас связь один-ко-многим (one-to-many).

Например, у нас определен следующий класс футбольной команды Team:

А класс Player, описывающий футболиста, мог бы выглядеть следующим образом:

Кроме обычных свойств типа Name, Position и Age здесь также определен внешний ключ. Внешний ключ состоит из обычного свойства и навигационного.

Свойство public Team Team { get; set; } в классе Player называется навигационным свойством – при получении данных об игроке оно будет автоматически получать данные из БД.

Аналогично в классе Team также имеется навигационное свойство – Players, через которое мы можем получать игроков данной команды.

Вторая часть внешнего ключа – свойство TeamId. Чтобы в связке с навигационным свойством образовать внешний ключ оно должно принимать одно из следующих вариантов имени:

  • Имя_навигационного_свойства+Имя ключа из связанной таблицы – в нашем случае имя навигационного свойства Team, а ключа из модели Team – Id, поэтому в нашем случае нам надо обозвать свойство TeamId, что собственно и было сделано в вышеприведенном коде.
  • Имя_класса_связанной_таблицы+Имя ключа из связанной таблицы – в нашем случае класс Team, а ключа из модели Team – Id, поэтому опять же в этом случае получается TeamId.

Как уже было сказано, внешний ключ позволяет получать связанные данные. Например, после генерации базы данных с помощью Code First таблица Players будет иметь следующее определение:

При определении внешнего ключа нужно иметь в виду следующее. Если тип обычного свойства во внешнем ключе определяется как int?, то есть допускает значения null, то при создании базы данных соответствующее поле так будет принимать значения NULL: [TeamId] INT NULL.

Однако если мы изменим в классе Player тип TeamId на просто intpublic int TeamId { get; set; }, то в этом случае соответствующее поле имело бы ограничение NOT NULL, а внешний ключ определял бы каскадное удаление:

Способы загрузки и получения связанных данных

В Entity Framework есть три способа загрузки данных:

  • eager loading(“жадная загрузка”)
  • explicit loading(“явная загрузка”)
  • lazy loading(“ленивая загрузка”)

Eager Loading

Суть Eager Loading заключается в том, чтобы использовать для подгрузки связанных по внешнему ключу данных метод Include. Например, получим всех игроков с их командами:

Без использования метода Include мы бы не могли бы получить связанную команду и ее свойства: p.Team.Name

Соответственно чтобы подгрузить к командам все данные по игрокам, мы можем написать так:

Explicit Loading

Явная загрузка предусмативает применение метода Load() для загрузки данных в контекст. Например:

Чтобы подгрузить данные, здесь идет обращение к методу db.Entry(), в который передается нужный объект. Для подгрузки связанного объекта, который не представляет коллекцию, используется метод Reference(). В этот метод переается навигационное свойство, по которому надо подгрузить данные.

Если связанные объект представляет коллекцию, то применяется метод Collection(), в который также передается навигационное свойство в виде строки.

Lazy Loading

Еще один способ представляет так называемая “ленивая загрузка” или lazy loading. При таком способе подгрузки при первом обращении к объекту, если связанные данные не нужны, то они не подгружаются. Однако при первом же обращении к навигационному свойству эти данные автоматически подгружаются из бд.

При использовании ленивой загрузки надо иметь в виду некоторые моменты при объявлении классов. Так, классы, использующие ленивую загрузку должны быть публичными, а их свойства должны иметь модификаторы public и virtual. Например, классы Player и Team могут иметь следующее определение:

В этом случае нам не потребуется использовать какие-то дополнительные методы, как Include или Load:

 

This entry was posted in C#. Bookmark the permalink.

Leave a Reply