ГЛАВА 17.2 ENTITY FRAMEWORK |
|
Оглавление |
|
§17.8 Навигационные свойства и загрузка данных ............................................. |
1 |
§17.9 Связь один к одному ..................................................................................... |
8 |
§17.10 Связь один ко многим............................................................................... |
20 |
§17.11 Миграции ................................................................................................... |
26 |
§17.8 Навигационные свойства и загрузка данных
В предыдущей теме в качестве модели был использован класс User,
представляющий пользователя и содержащий три свойства. Однако эта была очень простая модель. В реальности в нашей базе данных может быть не одна,
а несколько таблиц, которые связаны между собой различными связями.
Рассмотрим создание модели данных для информационной системы по поиску дипломных руководителей для студентов отделений среднего профессионального образования. Допустим, для каждого дипломного руководителя может быть определен набор примерных тем для дипломного проекта, которые он предлагает студентам. И, наоборот, одна примерная тема дипломного проекта может быть предложена только одним дипломным руководителем. То есть в данном случае у нас связь один-ко-многим (one-to- many).
Например, у нас определен следующий класс Professor:
Листинг 17.16
1 |
public class Professor |
2 |
{ |
3 |
public int Id { get; set; } |
4 |
public string Name { get; set; } |
5 |
public string Position { get; set; } |
6 |
public string PersonalData { get; set; } |
7 |
public ICollection<Thesis> Theses { get; set; } |
8 |
public Professor() |
9 |
{ |
10 |
this.Theses = new List<Thesis>(); |
11 |
} |
|
1 |
12 }
Здесь Name – это ФИО дипломного руководителя, Position – его
должность, PersonalData – информация об его профессиональной деятельности, Theses – внешний ключ, представляющий собой обобщенную коллекцию ICollection<Thesis> для хранения тем дипломных проектов
Thesis, предлагаемых им.
Интерфейс обобщенной коллекции ICollection<T> представляет ряд общих свойств и методов для всех обобщенных коллекций (например, методы
CopyTo, Add, Remove, Contains, свойство Count).
|
|
А класс Thesis, описывающий дипломный проект, мог бы выглядеть |
|
следующим образом: |
|||
|
|
Листинг 17.17 |
|
|
|
|
|
|
1 |
public class Thesis |
|
|
2 |
{ |
|
|
3 |
public int Id { get; set; } |
|
|
4 |
public string Name { get; set; } |
|
|
5 |
public int? ProfessorId { get; set; } |
|
|
6 |
public Professor Professor { get; set; } |
|
|
7 |
} |
|
Кроме обычного свойства Name (наименование темы дипломного проекта), здесь также определен внешний ключ. Внешний ключ состоит из обычного свойства и навигационного.
Свойство
public Professor Professor { get; set; }
в классе Thesis называется навигационным свойством - при получении данных об дипломном руководителе оно будет автоматически получать данные из базы данных.
Аналогично в классе Professor также имеется навигационное свойство
– Theses, через которое мы можем получать темы дипломных проектов,
предлагаемые данным преподавателем.
2
Вторая часть внешнего ключа - свойство ProfessorId. Чтобы в связке
с навигационным свойством образовать внешний ключ оно должно принимать
одно из следующих вариантов имени:
1.Имя_навигационного_свойства + Имя ключа из связанной таблицы
- в нашем случае имя навигационного свойства Professor, а ключа из модели Professor – Id, поэтому в нашем случае нам надо обозвать свойство ProfessorId, что собственно и было сделано в вышеприведенном коде.
2.Имя_класса_связанной_таблицы + Имя ключа из связанной таблицы - в нашем случае класс Professor, а ключа из модели
Professor - Id, поэтому опять же в этом случае получается
ProfessorId.
Как уже было сказано, внешний ключ позволяет получать связанные данные. Например, после генерации базы данных с помощью Code First
таблица Theses будет иметь следующее определение:
|
|
|
Листинг 17.18 |
|
|
|
|
||
1 |
CREATE TABLE [dbo].[Theses] ( |
|
||
2 |
[Id] |
INT |
IDENTITY (1, 1) NOT NULL, |
|
3 |
[Name] |
NVARCHAR (MAX) NULL, |
|
|
4 |
[ProfessorId] INT |
NULL, |
|
|
5 |
CONSTRAINT [PK_dbo.Theses] PRIMARY KEY CLUSTERED ([Id] ASC), |
|
||
6 |
CONSTRAINT [FK_dbo.Theses_dbo.Professors_ProfessorId] FOREIGN |
|
||
KEY ([ProfessorId]) REFERENCES [dbo].[Professors] ([Id]) |
|
|||
7 |
); |
|
|
|
При определении внешнего ключа нужно иметь в виду следующее. Если тип обычного свойства во внешнем ключе определяется как int?, то есть допускает значения null, то при создании базы данных соответствующее поле так будет принимать значения NULL:
[ProfessorId] INT NULL.
Однако если мы изменим в классе Thesis тип ProfessorId на просто
int:
public int ProfessorId { get; set; }, 3
то в этом случае соответствующее поле имело бы ограничение NOT NULL, а
внешний ключ определял бы каскадное удаление:
|
|
|
Листинг 17.19 |
|
|
|
|
||
1 |
CREATE TABLE [dbo].[Theses] ( |
|
||
2 |
[Id] |
INT |
IDENTITY (1, 1) NOT NULL, |
|
3 |
[Name] |
NVARCHAR (MAX) NULL, |
|
|
4 |
[ProfessorId] INT |
NOT NULL, |
|
|
5 |
CONSTRAINT [PK_dbo.Theses] PRIMARY KEY CLUSTERED ([Id] ASC), |
|
||
|
CONSTRAINT [FK_dbo.Theses_dbo.Professors_ProfessorId] FOREIGN |
|
||
6 |
KEY ([ProfessorId]) REFERENCES [dbo].[Professors] ([Id]) ON |
|
||
|
DELETE CASCADE |
|
|
|
7 |
); |
|
|
|
4
Способы загрузки и получения связанных данных
В Entity Framework есть три способа загрузки данных:
1.eager loading ("жадная загрузка")
2.explicit loading ("явная загрузка")
3.lazy loading ("ленивая загрузка")
Жадная загрузка
Суть жадной загрузки заключается в том, чтобы использовать для подгрузки связанных по внешнему ключу данных метод Include. Например,
получим темы дипломных работ, предлагаемые выбранным в списке руководителем:
Листинг 17.20
1 |
using (UserContext db = new UserContext()) |
|
2 |
{ |
|
3 |
var professors = |
|
db.Professors.Include("Theses").ToList(); |
||
|
||
4 |
foreach (Professor p in professors) |
|
5 |
{ |
|
6 |
if (p.Name == name) |
|
7 |
{ |
|
8 |
foreach (Thesis t in p.Theses) |
|
9 |
{ |
|
10 |
listBox1.Items.Add(t.Name); |
|
11 |
} |
|
12 |
} |
|
13 |
} |
|
14 |
} |
Без использования метода Include мы бы не могли бы получить связанные с руководителем дипломные проекты и его свойства.
Явная загрузка
Явная загрузка предусматривает применение метода Load() для загрузки данных в контекст. Например:
Листинг 17.21
1 |
using (UserContext db = new UserContext()) |
2 |
{ |
|
5 |