Как получить связанные объекты при помощи EF?

Bald

Предположим у нас есть следующая структура классов:

public class User
{ public int Id {get;set;} //прочие свойства public int RoleId {get;set;} public Role Role {get;set;}
}
public class Role
{ public int Id {get;set;} //прочие свойства public ICollection<user> Users {get;set;} public ICollection<permission> Permissions {get;set;} public Role() { Permissions = new List<permission>() }
}
public class Permission
{ public int Id {get;set;} //прочие свойства public ICollection<role> Roles {get;set;} public Permission() { Roles = new List<roles>(); }
}
</roles></role></permission></permission></user>

Как модифицировать указанные выше классы что бы можно было получить связанные сущности средствами Entity Framework?

2 ответа

Bald

Для того что бы получить связанные объекты средствами Entity Framework существует несколько способов:

  1. Eager loading - жадная загрузка;
  2. Lazy loading - ленивая загрузка;
  3. Explicitly lоading - явная загрузка;

<em>Жадная</em> загрузка - процесс при котором необходимо указать сущности которые необходимо загрузить сразу, это достигается путем указания необходимых сущностей при помощи метода <code>.Include()</code>

В этом случае для будет сформирован один запрос к бд который вернет все необходимые данные.

<em>Ленивая</em> загрузка - процесс при котором связанные сущности подгружаются при первом обращении, необходимые свойства должны быть объявлены с указанием модификатора доступа <code>virtual</code>

В данном случае при обращение к навигационному свойству будет формироваться запрос к бд для получения необходимых данных

<em>Явная</em> загрузка - процесс при котором связанные сущности подгружаются только если они явно подключены при помощи метода <code>.Load()</code>

в данном случае связанные сущности не будут подгружены до момента их подключения при помощи .Load()

Универсального решения о выборе между ленивой/явной и жадной загрузке - нет.

Загружать много редко используемой информации (особенно часто изменяемой) - не эффективно, еще более не эффективно использовать n+1 запросов вместо одного, так как ленивая загрузка будет означать выполнение отдельного запроса для каждого объект. Если нужно, то можно использовать .Load() вместо .Include()

Например:

Жадная загрузка:

var user = context.Roles.Where(x=>x.Name.Contains("Admin")).Include(x=>x.Permissions)

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

Установим модификатор доступа virtual у свойства Role у класса User

public virtual Role Role {get;set;}

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

//получаем необходимого пользователя
var user = context.Users.Where(x=>x.Id==5)
//При обращении к свойству будет выполнен запрос к бд получающий связанную сущность.
var userRole = user.Role;

Явная загрузка:

может быть использована при отключенной ленивой загрузке(context.Configuration.LazyLoadingEnabled = false;), либо при отсутствии модификатора доступа virtual у необходимого свойства

var role = context.Roles.Where(x=>x.Name.Contains("Admin")).Single();

что бы получить связанные сущности в этом случае необходимо поступить так:

var usersRole = context.Entry(role).Collection(x => x.Users).Load();


Bald

Если используются сложные объекты, например вы хотите получить Users вместе в Roles, можно пользоваться

var a = context.Users.Include(w=>w.Roles);

Но я не до конца понял ваш вопрос

licensed under cc by-sa 3.0 with attribution.