Добавил:
Преподаватель Колледжа информационных технологий Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лекции / Глава 17.2 Entity Framework 2

.pdf
Скачиваний:
46
Добавлен:
08.05.2022
Размер:
1.04 Mб
Скачать

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

{

 

3

var FirstProfessor = db.Professors.FirstOrDefault();

 

4

db.Entry(FirstProfessor).Collection("Theses").Load();

 

5

foreach (Thesis t in FirstProfessor.Theses)

 

6

{

 

7

listBox1.Items.Add(t.Name);

 

8

}

 

9

}

 

В данной программе метод FirstOrDefault находит первый элемент из коллекции Professors и присваивает переменной FirstProfessor.

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

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

11

Ленивая загрузка

Еще один способ представляет так называемая «ленивая загрузка» или lazy loading. При таком способе подгрузки при первом обращении к объекту,

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

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

могут иметь следующее определение:

Листинг 17.22

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 virtual ICollection<Thesis> Theses { get; set; }

8 public Professor()

9 {

10 this.Theses = new List<Thesis>();

11 }

12 }

13 public class Thesis

14 {

15 public int Id { get; set; }

16 public string Name { get; set; }

17 public int? ProfessorId { get; set; }

18 public virtual Professor Professor { get; set; }

19 }

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

Листинг 17.23

1 if (this.Professor.Theses.Count != 0)

12

2

{

3

for (int i = 0; i < this.Professor.Theses.Count; i++)

4

{

5

listBox1.Items.Add(this.Professor.Theses.ToList()[i].Name);

6

}

7

}

В данной программе происходит добавление в список listBox1

наименований тем дипломных проектов Professor.Theses.ToList()[i].Name,

закрепленных за преподавателем Professor.

§17.9 Связь один к одному

Строго говоря в Entity Framework нет как таковой связи один-к-одному,

так как ожидается, что обработчик будет использовать связь один-ко-многим.

Но все же нередко возникает потребность в наличие подобной связи между объектами в приложении, и в Entity Framework мы можем настроить данный тип отношений.

Рассмотрим стандартный пример подобных отношений: есть класс пользователя User, который хранит логин, пароль и роль, то есть данные учетных записей. А все данные профиля, такие как имя, номер группы (для студента), должность (для дипломного руководителя) и так далее, выделяются в класс профиля UserProfile.

 

Листинг 17.24

 

 

 

1

using System.Collections.Generic;

 

2

using System.ComponentModel.DataAnnotations;

 

3

using System.ComponentModel.DataAnnotations.Schema;

 

4

 

5

public class User

 

6

{

 

7

public int Id { get; set; }

 

8

public string Login { get; set; }

 

9

public string Password { get; set; }

 

10

public string Role { get; set; }

 

11

public UserProfile Profile { get; set; }

 

12

}

 

13

public class UserProfile

 

14

{

 

 

13

 

15

[Key]

16

[ForeignKey("User")]

17

public int Id { get; set; }

18

public string Name { get; set; }

19

public int NumberGroup { get; set; }

20

public string PersonalDate { get; set; }

21

public User User { get; set; }

22

public Professor Professor { get; set; }

23

}

В этой связи между классами класс UserProfile является дочерним или подчиненным по отношению к классу User. И чтобы установить связь одни к одному, у подчиненного класса устанавливается свойство идентификатора, которое называется также, как и идентификатор в основном классе. То есть в классе User свойство называется Id, то и в UserProfile

также свойство называется Id. Если бы в классе User свойство называлось бы

UserId, то такое же название должно было быть и в UserProfile.

И в классе UserProfile над этим свойством Id устанавливаются два атрибута: [Key], который показывает, то это первичный ключ, и

[ForeignKey], который показывает, что это также и внешний ключ. Причем

внешний ключ к таблице объектов User.

 

 

Соответственно классы User и UserProfile имеют ссылки друг на

друга.

 

 

В классе контекста определяются свойства для взаимодействия с

таблицами в базе данных:

 

 

Листинг 17.25

 

 

 

 

 

1

public class UserContext : DbContext

 

 

2

{

 

 

3

public UserContext()

 

 

4

{ }

 

 

5

public DbSet<User> Users { get; set; }

 

 

6

public DbSet<UserProfile> UserProfiles { get; set; }

 

 

7

public DbSet<Professor> Professors { get; set; }

 

 

8

public DbSet<Thesis> Theses { get; set; }

 

 

9

}

 

 

 

14

 

Для этих классов контекст данных будет создавать следующую таблицу

UserProfiles:

Листинг 17.26

1

CREATE TABLE [dbo].[UserProfiles] (

2

[Id]

INT

NOT NULL,

3

[Name]

NVARCHAR (MAX) NULL,

4

[NumberGroup]

INT

NOT NULL,

5

[PersonalDate] NVARCHAR (MAX) NULL,

6

CONSTRAINT [PK_dbo.UserProfiles] PRIMARY KEY CLUSTERED ([Id]

 

ASC),

 

 

7

CONSTRAINT [FK_dbo.UserProfiles_dbo.Users_Id] FOREIGN KEY

([Id]) REFERENCES [dbo].[Users] ([Id])

8

);

 

 

Посмотрим, как работать с моделями с такой связью. Рассмотрим сценарий регистрации пользователей в информационную систему.

Создадим форму для регистрации пользователей:

Рисунок 5

15

Реализация метода обработчика события нажатия на кнопку «Зарегистрироваться»:

 

 

Листинг 17.27

 

 

 

 

if (textBoxUserLogin.Text != ""

 

 

&& textBoxUserPassword.Text != ""

 

 

&& textBoxUserProfileName.Text != ""

С помощью составного условия проверяется

1

&& textBoxUserProfileNumberGroup.Text != ""

заполненность всех полей.

 

 

&& textBoxUserProfilePersonalDate.Text != ""

 

 

&& comboBoxUserRole.Text != "")

 

 

 

 

2

{

 

 

 

 

 

 

3

using (UserContext db = new UserContext())

Подключение контекста данных UserContext

 

 

 

 

 

4

{

 

 

 

 

 

 

 

User user = new User { Login =

Создание объекта user класса User и

 

textBoxUserLogin.Text, Password =

 

инициализация его свойств данными,

5

textBoxUserPassword.Text, Role =

 

 

введенными через соответствующие textBox

 

comboBoxUserRole.Text };

 

 

 

 

 

 

db.Users.Add(user);

Добавление созданного объекта user в

6

коллекцию сущностей Users из контекста

 

 

 

 

 

 

16

 

 

данных, отвечающую за хранение сущностей в

 

 

базе данных

 

 

 

 

db.SaveChanges();

Сохранение изменений результата запроса в базе

7

данных

 

 

 

 

 

 

 

if (comboBoxUserRole.Text == "Студент")

Если выбранное значение в раскрывающемся

8

списке comboBox это "Студент"

 

 

 

 

 

 

9

{

 

 

 

 

 

 

 

UserProfile userProfile = new UserProfile { Id =

 

 

user.Id, Name = textBoxUserProfileName.Text,

Создание объекта userProfile класса

 

NumberGroup =

UserProfile и инициализация его свойств

10

int.Parse(textBoxUserProfileNumberGroup.Text),

данными, введенными через соответствующие

 

PersonalDate = textBoxUserProfilePersonalDate.Text

textBox

 

};

 

 

 

 

 

 

Добавление созданного объекта userProfile в

 

db.UserProfiles.Add(userProfile);

коллекцию сущностей UserProfiles из

11

контекста данных, отвечающую за хранение

 

 

 

 

сущностей в базе данных

 

 

 

17

 

db.SaveChanges();

Сохранение изменений результата запроса в базе

12

данных

 

 

 

 

 

13

}

 

 

 

 

 

else if (comboBoxUserRole.Text == "Преподаватель")

Если выбранное значение в раскрывающемся

14

списке comboBox это "Преподаватель"

 

 

 

 

 

15

{

 

 

 

 

 

UserProfile userProfile = new UserProfile { Id =

Создание объекта userProfile класса

 

UserProfile и инициализация его свойств

 

user.Id, Name = textBoxUserProfileName.Text,

 

данными, введенными через соответствующие

16

NumberGroup = 0, PersonalDate =

textbox (для преподавателя номер группы будет

 

textBoxUserProfilePersonalDate.Text };

 

по умолчанию равен 0)

 

 

 

 

 

 

 

Добавление созданного объекта userProfile в

 

db.UserProfiles.Add(userProfile);

коллекцию сущностей UserProfiles из

17

контекста данных, отвечающую за хранение

 

 

 

 

сущностей в базе данных

 

 

 

 

db.SaveChanges();

Сохранение изменений результата запроса в базе

18

данных

 

 

 

 

 

18

 

 

Создание объекта professor класса Professor

 

Professor professor = new Professor { Id =

и инициализация его свойств данными,

 

userProfile.Id, Name =

введенными через соответствующие textbox

19

textBoxUserProfileName.Text, PersonalData =

(при регистрации преподавателя создается

 

textBoxUserProfilePersonalDate.Text, Position =

последовательно две сущности – для хранения

 

textBoxUserProfileNumberGroup.Text };

профиля преподавателя как пользователя

 

 

системы и дипломного руководителя)

 

 

 

 

 

Добавление созданного объекта professor в

 

db.Professors.Add(professor);

коллекцию сущностей Professors из контекста

20

данных, отвечающую за хранение сущностей в

 

 

 

 

базе данных

 

 

 

 

db.SaveChanges();

Сохранение изменений результата запроса в базе

21

данных

 

 

 

 

 

22

}

 

 

 

 

23

}

 

 

 

 

 

this.MainForm.Visible = true;

Переход в форму авторизации после успешной

24

регистрации

 

 

 

 

 

25

this.Visible = false;

Скрытие формы регистрации

 

 

 

26

}

 

 

 

 

 

19

 

Обратите внимание, что при создании двух объектов, связанных между собой отношением один ко многим,

необходимо инициализировать атрибут Id подчиненного объекта (в нашей случае подчиненным является userProfile

в паре user-userProfile и professor в паре userProfile-professor) значением атрибута Id родительского объекта. Например, в строке 10 и 16 при создании объекта userProfile свойству Id было присвоено значение user.Id,

то есть Id родительского объекта user, который был предварительно создан.

Рассмотрим пример редактирования данных. Добавим возможность редактирования логина, пароля и информации

«О себе» после входа в личную страницу пользователя в информационной системе. Создадим следующую форму для редактирования данных учетной записи пользователя:

Рисунок 6

Реализация метода обработчика события нажатия на кнопку подтверждения изменений « »:

20