2013-10-02 13 views
8

Mam dwie klasy model:operacja Insert z wielu do wielu relacji przy użyciu EF

public class Candidate 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Job> Jobs { get; set; } 
} 

public class Job 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Candidate> Candidates { get; set; } 
} 

nazwa My DbContext jest JobsContext.

Powyższy kod generuje mnie 3 stoły Kandydaci, Praca & CandidatesJobs (automatycznie wygenerowany przez EF)

Teraz mam rekordy w zawodach tabeli: id = 1, name = "Sprzedaż" id = 2, Name = "Inżynier".

Chcę skojarzyć nowy kandydat, który wstawię do tabeli Kandydaci z 2 rekordami z tabeli Zadania.

Przed wstawieniem kandydata Znam tabelę identyfikatorów zleceń & Nie chcę nawiązywać połączeń z bazą danych, aby uzyskać więcej informacji z tabeli zadań.

Jak zrobić to za pomocą Entity Framework 5?

Odpowiedz

17

Co powiesz na to?

Job salesJob; // already fetched from db 
Job engineerJob; // already fetched from db 

Candidate candidate = new Candidate(); 
candidate.Name = "John Doe"; 
candidate.Jobs = new List<Job>(); // you could also do this in the constructor of Candidate 
candidate.Jobs.Add(salesJob); 
candidate.Jobs.Add(engineerJob); 

context.SaveChanges(); 

Zadziała tylko jeśli już pobrane zadania z bazy danych w tej samej instancji DbContext, EF jeszcze pomyśli, że miejsca pracy są „nowe” i stara się je wstawić. Jeśli masz tylko identyfikatory, można spróbować wykonać następujące czynności:

var salesJob = new Job { Id = salesJobId }; 
var engineerJob = new Job { Id = engineerJobId }; 

context.Jobs.Attach(salesJob); 
context.Jobs.Attach(engineerJob); 

candiate.Jobs.Add(salesJob); 
candiate.Jobs.Add(engineerJob); 
context.SaveChanges(); 
+0

W drugim bloku kodu, doda on nowe rekordy. – cbeckner

+0

@ cakerner o tym, jak nazwiesz 'context.Jobs.Attach (new Job {Id = salesJobId});' first? –

+0

To by to zrobiło. – cbeckner

6

Dostępne są dwie opcje.

Jeśli zamierzasz kłaść ten sam kontekst i obiekty kandydujące, możesz po prostu dodać istniejące obiekty kandydata do zadania. Na przykład: Załóż kandydatów i zapisać je do bazy danych:

JobsContext context = new JobsContext(); 
var candidate1 = new Candidate() { Name = "John Smith" }; //id 1 
var candidate2 = new Candidate() { Name = "Jane Smith" }; //id 2 
var candidate3 = new Candidate() { Name = "John Doe" }; //id 3 
context.Candidates.Add(candidate1); 
context.Candidates.Add(candidate2); 
context.Candidates.Add(candidate3); 
context.SaveChanges(); 

Następnie utwórz zadanie:

var job = new Job() { Name = "Good Job" }; //id 1 

Wreszcie dodać kandydatów do nowej job zmiennej, dodać zadanie do kontekst i zapisz zmiany.

job.Candidates.Add(candidate1); 
job.Candidates.Add(candidate2); 
context.Jobs.Add(job); 
context.SaveChanges(); 

LUB

Jeśli używasz innego kontekstu z utworzonego kandydatów z jednej, to można utworzyć nowy obiekt kandydata i dołączyć go do kontekstu przed dodaniem go do praca.

//different context from above example 
JobsContext newContext = new JobsContext(); 
//this can be a new or existing job, using the job from the example above here 
var existingJob = newContext.Jobs.FirstOrDefault(j => j.Id == 1); 

Tworzenie nasz obiekt kandydata poprzez ustawienie tylko identyfikator

var existingCandidate3 = new Candidate() { Id = 3 }; 

dołączyć obiekt do nowego kontekstu. Uwaga: jeśli kontekst z powyższego przykładu jest nadal w pobliżu, nie pozwoli ci to zrobić, ponieważ już śledzi kandydata.

newContext.Candidates.Attach(existingCandidate3); 

Ustaw stan na niezmienionym poziomie od nie chcemy tworzyć nowego kandydata, wystarczy użyć istniejącego.

newContext.Entry(existingCandidate3).State = System.Data.EntityState.Unchanged; 

Dodaj i zapisz zmiany.

existingJob.Candidates.Add(existingCandidate3); 
newContext.SaveChanges(); 

Zrobione!

+0

W pierwszej opcji twoja 2 wywołania bazy danych 1), aby wstawić kandydata 2) skojarzyć kandydata z zadaniem. ** Miałem nadzieję, że zrobię to na jednym INSERT **, np. JobsContext.candidates.Add (kandydat), który zawiera istniejące zadanie. Zobacz: [link] (http://nileshhirapra.blogspot.in/2012/03/entity-framework-insert-operation-with.html) –

+0

Możesz usunąć wywołanie 'SaveChanges' po utworzeniu kandydatów w pierwszym przykładzie i Wykonaj jedno połączenie z 'SaveChanges' po utworzeniu zarówno kandydatów, jak i zadania. Jednak EF nadal przetłumaczy to na kilka różnych wywołań bazy danych (co najmniej * 1 dla każdej tabeli). Twoje pytanie brzmiało tak, jakbyś chciał uniknąć "SELECT" przeciwko tabeli kandydatów przed dodaniem ich do pracy. – cbeckner

+1

Wykonałem fexing kodu, aby poprawić zmianę stanu, brakowało "Entity" w twoim kodzie: poprawne jest System.Data.Entity.EntityState.Unchanged –

0

Bardzo prostym rozwiązaniem jest stworzenie widok spisu odnośnika dokładnie tak, jak w tabeli (view_tablename_raw). Następnie zaktualizuj ten widok w EF jako encji bez kluczy obcych. Z ich użycia kontekst .view_tablename_raw.Add (...) i będzie działać płynnie.