Вставки «многие ко многим» с Entity Framework - PullRequest
1 голос
/ 09 апреля 2011

Скажем, у меня есть две сущности с примерно 20 свойствами на одну сущность и отношение «многие ко многим», например:

User (Id int,Name string, .......)
Issue (Id int,Name string, .......)
IssueAssignment (UserId,RoleId)

Я хочу создать новую проблему и назначить ее нескольким существующим пользователям.,Если у меня есть такой код:

foreach(var userId in existingUserIds)
{
   int id = userId
   var user = _db.Users.First(r => r.Id == id);        
   issue.AssignedUsers.add(user);     
}

_db.Users.AddObject(user);
_db.SaveChanges();

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

  1. SELECT TOP (1) * ОТ пользователя, ГДЕ UserId = userId
  2. SELECT * FROM IssueAssignment ON User.Id = userId
  3. INSERT INTO User ....
  4. INSERT INTO IssueAssignment

Мои вопросы:
(a) почему (1) и (2) имеютслучиться вообще?
(b) Оба (1) и (2) возвращают все поля. Нужно ли мне делать проекцию объекта, чтобы ограничить поля, тоже кажется ненужной работой.

Спасибо за помощь

1 Ответ

4 голосов
/ 10 апреля 2011

У меня есть несколько возможных подсказок для вас:

  1. Вот как ведет себя EF._db.Users - это на самом деле запрос, а вызов First для запроса означает выполнение запроса в базе данных.
  2. Полагаю, вы используете EFv4 с шаблоном T4, и отложенная загрузка включена.Шаблоны T4 создают «умные» объекты, которые могут исправить свои свойства навигации, поэтому после добавления User к Issue он внутренне вызывает исправление и пытается добавить Issue к User.Это в свою очередь вызывает ленивую загрузку всех проблем, связанных с пользователем.

Таким образом, хитрость заключается в использовании фиктивных объектов вместо реального пользователя.Вы знаете идентификатор и хотите создавать отношения между новой проблемой и существующим пользователем.Попробуйте это (работает с EFv4 + и POCO):

foreach(var userId in existingUserIds)
{
   var user = new User { Id = userId };
   var _db.Users.Attach(user); // User with this Id mustn't be already loaded       
   issue.AssignedUsers.Add(user);     
}

context.Issues.AddObject(issue);
context.SaveChanges();
...