2013-01-13 12 views
7

Chcę używać Entity Framework POCO w trybie odłączonym (z kontekstu). W moim scenariuszu tworzę nowy obiekt nadrzędny i chcę dołączyć do niego istniejący obiekt potomny, a następnie zapisać go w bazie danych.
Poniższy kod w sposób niepożądany wprowadza nowy rekord kursu podczas zapisywania nowego rekordu ucznia, kiedy chcę, aby istniejący rekord kursu był powiązany z nowym rekordem ucznia.Entity Framework: dodanie istniejącego potomka POCO do nowego Parent POCO, tworzy nowe dziecko w DB

Jak mogę to zrobić w Entity Framework, gdzie ...

  • obiekty mogą być odłączone od kontekstu. (tj. Zapytany w jednym kontekście, a następnie zapisany w innym kontekście)
  • Nie trzeba ponownie przesyłać zapytania do rekordu podrzędnego z bazy danych tylko po to, aby dołączyć go do elementu nadrzędnego podczas zapisywania do bazy danych. Naprawdę chcę uniknąć dodatkowych wypraw do bazy, gdy już mam to jako obiekt w pamięci.

Ta strona przedstawia schemat bazy danych, że poniższy kod jest oparty na 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; 
    } 
} 

Odpowiedz

17

Wierzę, że istnieje kilka sposobów na osiągnięcie tego. Można określić, że jednostka Oczywiście pozostaje niezmieniona zamiast dodał wzdłuż tych linii:

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

Albo poinstruować swój kontekst, że pracujesz z istniejącej jednostki:

ctx.Courses.Attach(course); 

Więcej informacji tutaj: http://msdn.microsoft.com/en-us/data/jj592676.aspx

EDIT

Z mojego rozwiązania pobierane są niektóre próbki. Sprawdziłem, że działają zgodnie z oczekiwaniami. We wszystkich przypadkach mamy rekord wydawcy w bazie danych o identyfikatorze = 2 i nazwie = "Addison Wesley" (nieistotny dla przykładu, ale tylko na dobrą miarę).

Approach 1 - Ustawianie podmiot publiczny

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(); 
} 

Podejście 2 - Korzystanie Attach metoda

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(); 
} 

Podejście 3 - Ustawianie obce wartość klucza

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

Na to ostatnie podejście do pracy, że muszę dodać dodatkową właściwość publisherID, to musi być nazwane według NavigationPropertyName + „id” konwencja być odebrany przez EF auotmatically:

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

używam tutaj kod EF5 Po pierwsze, ale jest bardzo podobny do POCO.

+0

Druga opcja prawie działa, ale otrzymuję komunikat "Obiekt nie może zostać przyłączony, ponieważ jest już w kontekście obiektu." błąd na "ctx.Students.AddObject (stud);" linia. Zakładam, że nie mogę tego zrobić, póki jeszcze robię "stud.Courses.Add (oczywiście);" przed tym . Chciałbym nadal korzystać z kolekcji Courses w obiekcie typu stadnina. – MakkyNZ

+0

Cóż, nie mam rozwiązania przydatnego do przetestowania go, ale spróbuj najpierw go załączyć, a następnie dodać do studenta. Mam nadzieję, że w ten sposób nie zostanie oznaczony jako "dodany" przez EF. –

+0

to naprawdę nie jest idealne. Chciałbym, aby relacja parent-> child odbywała się najpierw na poziomie obiektu, ponieważ może nie być jeszcze gotowa do zapisania w db. Może powinienem po prostu usunąć wszystkie relacje między podmiotami, które EF generuje i samodzielnie to kontrolować? – MakkyNZ

0

Entity Framework nie pozwala relacje, które przekraczają konteksty.

Jeśli umieścisz czytanie kursu i połączenie kursu ze studentem w ramach tej samej instrukcji użycia, to zadziała.

0

Próbowałem też drugiej opcji, która zadziałała dla mnie. Podobało mi się pierwszeństwo relacji rodzic-> dziecko na poziomie obiektu i zapisanie w db. Może powinienem po prostu usunąć wszystkie relacje między podmiotami, które EF generuje i samodzielnie to kontrolować.

Powiązane problemy