Entity Framework: добавление существующего дочернего POCO к новому Parent POCO, создание нового дочернего элемента в DB

Я хочу использовать Entity Framework POCO в отключенном (из контекста) режиме. В моем сценарии я создаю новый объект Parent и хочу привязать к нему существующий дочерний объект, а затем сохранить его в db.
Код ниже нежелательно вставляет новую запись курса при сохранении новой записи Студента, когда вместо этого я хочу, чтобы существующая запись курса была связана с новой записью Студента.

Как я могу это сделать в Entity Framework, где …

  • объекты могут быть отключены от контекста. (т. е. запрашивается в одном контексте, а затем сохраняется в другом контексте)
  • Мне не нужно повторно запрашивать дочернюю запись из базы данных, чтобы я мог прикрепить ее к родительскому элементу, когда я сохраняю db. Я действительно хочу избежать дополнительных поездок в db, когда у меня уже есть это как объект в памяти.

На этой странице показана диаграмма базы данных, в которой приведенный ниже код основан на http://entityframeworktutorial.net/EF4_EnvSetup.aspx#.UPMZ4m-UN9Y

class Program { static void Main(string[] args) { //get existing course from db as disconnected object var course = Program.getCourse(); //create new student var stud = new Student(); stud.StudentName = "bob"; //assign existing course to the student stud.Courses.Add(course); //save student to db using (SchoolDBEntities ctx = new SchoolDBEntities()) { ctx.Students.AddObject(stud); ctx.SaveChanges(); } } static Course getCourse() { Course returnCourse = null; using (var ctx = new SchoolDBEntities()) { ctx.ContextOptions.LazyLoadingEnabled = false; returnCourse = (from s in ctx.Courses select s).SingleOrDefault(); } return returnCourse; } } 

Я считаю, что есть несколько способов добиться этого. Вы можете указать, что объект курса не изменен, а не добавлен в следующие строки:

 ctx.Entry(course).State = EntityState.Unchanged; 

Или укажите свой контекст, что вы работаете с существующим объектом:

 ctx.Courses.Attach(course); 

Подробнее здесь: http://msdn.microsoft.com/en-us/data/jj592676.aspx

РЕДАКТИРОВАТЬ

Из моего решения есть несколько пробных проб, я проверял, что они работают должным образом. Во всех случаях у нас есть запись Publisher в базе данных с ID = 2 и Name = “Addison Wesley” (не относится к этому примеру, но только для хорошей меры).

Подход 1 – Установка состояния сущности

 using (var context = new Context()) { var book = new Book(); book.Name = "Service Design Patterns"; book.Publisher = new Publisher() {Id = 2 }; // Only ID is required context.Entry(book.Publisher).State = EntityState.Unchanged; context.Books.Add(book); context.SaveChanges(); } 

Подход 2 – Использование метода Attach

 using (var context = new Context()) { var book = new Book(); book.Name = "Service Design Patterns"; book.Publisher = new Publisher() { Id = 2 }; // Only ID is required context.Publishers.Attach(book.Publisher); context.Books.Add(book); context.SaveChanges(); } 

Подход 3 – Установка значения внешнего ключа

 using (var context = new Context()) { var book = new Book(); book.Name = "Service Design Patterns"; book.PublisherId = 2; context.Books.Add(book); context.SaveChanges(); } 

Для этого последнего подхода к работе мне нужно было добавить дополнительное свойство PublisherId, оно должно быть названо в соответствии с соглашением NavigationPropertyName + ‘Id’, которое должно быть выбрано EF auotmatically:

 public int PublisherId { get; set; } public Publisher Publisher { get; set; } 

Я использую здесь EF5 Code First, но он очень похож на POCO.

Entity Framework не позволяет отношениям, которые пересекают контексты.

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

Я также попробовал второй вариант, который это сработало для меня. Мне действительно нравились отношения parent-> child, происходящие на уровне объекта, и сохранение в db. Возможно, мне нужно просто удалить все отношения между сущностями, которые генерирует EF, и вручную управлять ими самостоятельно.