Лекции / Глава 17. Entity Framework
.pdf§17.10 Связь один ко многим
Связь один-ко-многим реализуется, если одна модель хранит ссылку на один объект другой модели, а вторая модель может ссылаться на коллекцию объектов первой модели. Например, у одного дипломного руководителя может существовать несколько тем для дипломных проектов, которые он может предложить студентам:
Листинг 17.30
1 |
public class Professor |
|
2 |
{ |
|
3 |
[Key, ForeignKey("UserProfile")] |
|
4 |
public int Id { get; set; } |
|
5 |
public string Name { get; set; } |
|
6 |
public string Position { get; set; } |
|
7 |
public string PersonalData { get; set; } |
|
8 |
public virtual UserProfile UserProfile { get; set; } |
|
9 |
public virtual ICollection<Thesis> Theses { get; set; |
|
} |
||
|
||
10 |
public Professor() |
|
11 |
{ |
|
12 |
this.Theses = new List<Thesis>(); |
|
13 |
} |
|
14 |
} |
|
|
|
|
15 |
public class Thesis |
|
16 |
{ |
|
17 |
public int Id { get; set; } |
|
18 |
public string Name { get; set; } |
|
19 |
public int? ProfessorId { get; set; } |
|
20 |
public virtual Professor Professor { get; set; } |
|
21 |
} |
|
|
|
Обычное свойство ProfessorId и навигационное свойство Professor
будет представлять собой внешний ключ подчиненной сущности Thesis.
Таким же образом в классе Team создается навигационное свойство Players,
представляющее собой интерфейс обобщенной коллекции
ICollection<Thesis>, через которое мы можем получать предлагаемые темы дипломных работ определенного преподавателя.
51
Рассмотрим реализацию метода добавления предлагаемых тем в коллекцию дипломного руководителя. Создадим следующую форму для добавления и просмотра тем:
Рисунок 39
52
Реализация метода обработчика события нажатия на кнопку «Добавить»:
|
|
|
Листинг 17.31 |
|
|
|
|
1 |
Thesis thesis = null; |
|
Создание объекта класса Thesis |
|
|
|
|
|
|
|
|
2 |
using (UserContext db = new UserContext()) |
|
Подключение контекста данных UserContext |
|
|
|
|
|
|
|
|
3 |
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
Цикл для обработки элементов коллекции |
|
|
|
db.Professors (коллекция сущностей |
|
|
|
Professors из базы данных). |
|
foreach (Professor professor in |
|
Метод Include применяется для упреждающей |
|
|
загрузки - это процесс, при котором запрос для |
|
4 |
db.Professors.Include("Theses")) |
|
|
|
|
одного типа сущности также загружает связанные |
|
|
|
|
|
|
|
|
сущности в составе запроса (в данном случае |
|
|
|
совместно с Professor загружается связанная |
|
|
|
сущность Theses). |
|
|
|
|
5 |
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
Проверка на совпадение имени дипломного |
|
if (this.Professor.Name == professor.Name) |
|
руководителя, для которого применяется |
6 |
|
добавление новой темы, с именем каждого |
|
|
|
||
|
|
|
|
|
|
|
дипломного руководителя из базы данных. |
|
|
|
|
|
|
53 |
|
7 |
{ |
|
|
||
|
|
|
|
Если дипломный руководитель найден в базе |
|
|
данных, то вызывается конструктор для объекта |
|
|
thesis = new Thesis() { Name = |
|
|
thesis (тема дипломного проекта) и происходит |
|
8 |
richTextBoxTheme.Text, ProfessorId = professor.Id |
|
инициализация его свойств. Атрибуту |
||
|
||
|
}; |
|
|
ProfessorId присваивается Id объекта |
|
|
professor, найденного в базе данных. |
|
|
|
|
9 |
} |
|
|
||
|
|
|
10 |
} |
|
|
|
|
|
Добавление созданного объекта thesis в |
|
|
коллекцию сущностей Theses из контекста |
|
11 |
db.Theses.Add(thesis); |
|
|
данных, отвечающую за хранение сущностей в |
|
|
базе данных |
foreach (Professor professor in
12db.Professors.Include("Theses"))
13{
14if (this.Professor.Name == professor.Name)
15{
54
|
|
|
|
|
|
Добавление в коллекцию Theses объекта |
||
16 |
professor.Theses.Add(thesis); |
professor новой темы дипломного проекта |
||||||
|
|
|
|
|
|
|
thesis |
|
|
|
|
|
|
|
|
|
|
17 |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db.SaveChanges();} |
|
|
Сохранение изменений результата запроса в базе |
||||
19 |
|
|
|
данных |
||||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
Реализация метода обработчика события нажатия на кнопку « |
Изменить |
»: |
|
||||
|
|
|
|
|
|
|
|
Листинг 17.32 |
|
|
|
|
|
|
|||
|
|
1 |
|
using (UserContext db = new UserContext()) |
|
|||
|
|
2 |
|
{ |
|
|
|
|
|
|
3 |
|
foreach (Thesis thesis in db.Theses) |
|
|||
|
|
4 |
|
{ |
|
|
|
|
|
|
5 |
|
if (thesis.Name == (string)listBoxTheme.SelectedItem) |
|
|||
|
|
6 |
|
{ |
|
|
|
|
|
|
7 |
|
thesis.Name = richTextBoxEditTheme.Text; |
|
|||
|
|
8 |
|
} |
|
|
|
|
|
|
9 |
|
} |
|
|
|
|
|
|
10 |
|
db.SaveChanges(); |
|
|
|
|
|
|
11 |
|
} |
|
|
|
|
55
При удалении объектов, связанных отношением «один-ко-многим» нам надо учитывать то, что по умолчанию даже если внешний ключ допускает значение null (как в данном случае свойство ProfessorId в классе Thesis),
мы не сможем просто так удалить одну модель, если она имеет ссылки на другую модель. Например, удаление дипломного руководителя в данном случае приведет к ошибке, если какой-нибудь объект Professor имеет ссылку на эту дипломный проект. В этом случае нам надо установить для внешнего ключа ProfessorId в таблице дипломных проектов ограничение
ON DELETE SET NULL. Данное ограничение позволит при удалении связанного объекта устанавливать для внешнего ключа значение null.
§17.11 Миграции
В реальных проектах модели данных изменяются по мере реализации функций. При добавлении или изменении новых сущностей или свойств схемы базы данных должны быть соответствующим образом изменены для синхронизации с приложением. Функция миграции в EF позволяет последовательно применять изменения схемы к базе данных, чтобы синхронизировать ее с моделью данных в приложении без потери существующих данных.
Добавим к существующему классу Thesis свойство для хранения аннотации к дипломному проекту:
Листинг 17.33
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 virtual Professor Professor { get; set; } |
||
7 |
|
public string Annotation { get; set; } |
|
|
8 |
} |
|
|
Для миграции в Visual Studio перейдем к окну Консоль диспетчера
пакетов, которое можно найти внизу VS. Если такого окна нет, то его можно
открыть, перейдя к меню Вид → Другие окна → Консоль диспетчера пакетов. 56
Для добавления функционала миграций введем в это окно следующую команду:
enable-migrations
После ввода команды нажмем на Enter. И в результате выполнения данной команды в проект будет добавлена папка Migrations, в которой будут два файла: Configration.cs (содержит базовую конфигурацию миграций) и
файл начальной миграции, название которого может отличаться. Файл начальной миграции устанавливает, как база данных определяется на данный момент.
Далее выполним в консоли следующую команду:
add-migration "AddAnnotationMigration"
И после выполнения этой команды в папку Migrations будет добавлена новая миграция.
В миграции определяются два метода: Up() и Down(). В методе Up с
помощью вызова метода AddColumn добавляется новый столбец Annotation
в уже имеющуюся таблицу dbo.Theses. Метод Down удаляет столбец на случай, если они существуют. Фактически эти методы равнозначны выражению ALTER в языке SQL, которое меняет структуру базы данных и ее таблиц.
И в завершении чтобы выполнить миграцию, применим этот класс,
набрав в той же консоли команду:
update-database
Эта команда обновит базу данных, добавив в нее новый столбец. Причем данные, которые уже были в таблицы, сохранятся.
Если база данных уже используется в производстве, развернута на сервере, где бы не можем произвести миграции, то мы можем сгенерировать по миграции скрипт. Для этого надо ввести следующую команду
update-database -script
В итоге будет сгенерирован скрипт SQL, который можно выполнить для используемой базы данных.
57