Лекции / Глава 17.2 Entity Framework 2
.pdfЛистинг 17.28
|
|
Создание объекта SelectedUser для хранения |
1 |
User SelectedUser = null; |
пользователя, у которого надо изменить значения |
|
||
|
|
атрибутов |
|
|
|
2 |
using (UserContext db = new UserContext()) |
Подключение контекста данных UserContext |
|
||
|
|
|
3 |
{ |
|
|
|
|
|
|
Цикл для обработки элементов коллекции |
4 |
foreach (User user in db.Users) |
db.Users (коллекция сущностей Users из базы |
|
||
|
|
данных) |
|
|
|
5 |
{ |
|
|
|
|
|
|
Проверка на совпадение логина пользователя |
|
|
this.User, для которого выбрана опция |
6 |
if(user.Login == this.User.Login) |
изменения данных, с логином каждого |
|
|
|
|
|
пользователя из базы данных |
|
|
|
7 |
{ |
|
|
|
|
|
|
При совпадении логина – присваиваем |
8 |
SelectedUser = user; |
переменной SelectedUser ссылку на объект |
|
||
|
|
user (найденный элемент из базы данных) |
|
|
|
21
9 |
} |
|
|
|
|
10 |
} |
|
|
|
|
11 |
SelectedUser.Login = textBoxLogin.Text; |
Изменение логина у найденного пользователя |
|
||
|
|
|
12 |
SelectedUser.Password = textBoxPassword.Text; |
Изменение пароля у найденного пользователя |
|
||
|
|
|
|
SelectedUser.Profile.PersonalDate = |
Изменение данных «О себе» у найденного |
13 |
|
|
|
textBoxPersonalData.Text; |
пользователя |
|
|
|
|
|
Сохранение изменений результата запроса в базе |
14 |
db.SaveChanges(); |
данных |
|
|
|
|
|
|
15 |
} |
|
|
|
|
|
MessageBox.Show("Изменения сохранены", |
Вывод сообщения об успешности завершения |
16 |
|
|
"Сообщение"); |
операции |
|
|
|
|
17 |
this.Visible = false; |
Скрытие текущей формы |
|
||
|
|
|
|
|
Открытие формы просмотра учетной записи |
18 |
FormStudentAccount.Visible = true; |
студента |
|
|
|
|
|
|
При удалении надо учитывать следующее: так как объект UserProfile требует наличие объекта User и зависит от этого объекта, то при удалении связанного объекта User надо будет удалить и связанный с ним объект UserProfile,
поскольку по умолчанию у нас не предусмотрено каскадное удаление при данной связи. Если же будет удален объект
UserProfile, на объект User это никак не повлияет:
22
|
|
Листинг 17.29 |
|
|
|
1 |
using(UserContext db = new UserContext()) |
Подключение контекста данных UserContext |
|
|
|
2 |
{ |
|
|
|
|
|
|
Цикл для обработки элементов коллекции |
|
|
db.Users (коллекция сущностей Users из базы |
3 |
foreach(User user in db.Users.ToList()) |
данных). Здесь коллекция db.Users |
|
|
преобразуется из DbSet в коллекцию List с |
|
|
помощью метода ToList(). |
|
|
|
4 |
{ |
|
|
|
|
|
|
Проверка на совпадение Id пользователя со |
|
|
значением, выбранным в списке listBoxUsers. |
5 |
if (user.Id == (string)listBoxUsers.SelectedItem) |
Так как свойство SelectedItem возвращает |
|
|
значение в типе данных object, необходимо |
|
|
преобразование в строковый тип (string). |
|
|
|
6 |
{ |
|
|
|
|
|
|
Проверка на ненулевое значение атрибута |
7 |
if (user.Profile != null) |
UserProfile у сущности User (наличие у |
|
|
пользователя профиля с личными данными) |
|
|
|
|
23 |
|
8 |
{ |
|
|
|
|
|
|
|
|
Если профиль существует, то происходит |
|
|
|
удаление профиля с помощью метода Remove. |
|
9 |
db.UserProfiles.Remove(user.Profile); |
Метод Remove применяется по отношению к |
|
коллекции UserProfiles из контекста данных и |
|||
|
|
||
|
|
в качестве параметра в него передается ссылка на |
|
|
|
удаляемый объект user.Profile. |
|
|
|
|
|
10 |
} |
|
|
|
|
|
|
|
|
Удаление пользователя с помощью метода |
|
|
|
Remove, который применяется по отношению к |
|
11 |
db.Users.Remove(user); |
коллекции Users из контекста данных и в |
|
|
|
качестве параметра в него передается ссылка на |
|
|
|
удаляемый объект user |
|
|
|
|
|
12 |
db.SaveChanges();}}} |
Сохранение изменений результата запроса в базе |
|
данных |
|||
|
|
||
|
|
|
24
§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>, через которое мы можем получать предлагаемые темы дипломных работ определенного преподавателя.
25
Рассмотрим реализацию метода добавления предлагаемых тем в коллекцию дипломного руководителя. Создадим следующую форму для добавления и просмотра тем:
Рисунок 7
26
Реализация метода обработчика события нажатия на кнопку «Добавить»:
|
|
|
Листинг 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 |
|
добавление новой темы, с именем каждого |
|
|
|
||
|
|
|
|
|
|
|
дипломного руководителя из базы данных. |
|
|
|
|
|
|
27 |
|
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{
28
|
|
|
|
|
|
Добавление в коллекцию 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 |
|
} |
|
|
|
|
29
При удалении объектов, связанных отношением «один-ко-многим» нам надо учитывать то, что по умолчанию даже если внешний ключ допускает значение 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. Если такого окна нет, то его можно
открыть, перейдя к меню Вид → Другие окна → Консоль диспетчера пакетов. 30