2011-10-25 14 views
14

Sto lavorando a un'applicazione WPF utilizzando Entity Framework 4.0. Quando ho provato a salvare l'oggetto, ho ottenuto un'eccezione della chiave primaria, ma la chiave primaria è un campo AutoIncremented e non riesco a capire il motivo dell'eccezione.Impedisci a Entity Framework di inserire valori per le proprietà di navigazione

Quindi dopo aver provato questo e quello, e un po 'di debugging e utilizzando il SQL Profiler, ho scoperto che prima di inserire il mio oggetto, un record deve essere inserito nella tabella genitore, come imposto la proprietà di navigazione di quell'oggetto .

Quindi il punto cruciale è se un tentativo di inserire un oggetto Employee e impostare il suo dipartimento come Employee.Department = deptObject, quindi un nuovo record è impostato per essere inserito sull'oggetto del dipartimento.

Gentilmente suggeritemi in qualche modo in base al quale gli oggetti di proprietà di navigazione non verranno inseriti nel database, nessuna proprietà o alcun metodo, Qualsiasi cosa.

Grazie

+0

Qual è la eccezione chiave primaria? Potrebbe darsi che tu non abbia la proprietà chiave primaria del tuo modello 'StoreGeneratedPattern' impostata su' Identity'. Se questo non è il caso, ti preghiamo di fornire alcuni esempi di codice da esaminare? – philt5252

risposta

40

Questo è il modo in cui funziona EF se si utilizzano le entità distanti in modo errato. Suppongo che si sta utilizzando qualcosa di simile:

var employee = new Employee(); 
employee.Department = GetDepartmentFromSomewhere(departmentId); 

... 

using (var context = new YourContext()) 
{ 
    context.Employees.AddObject(employee); 
    context.SaveChanges(); 
} 

Questo codice preparato entità dipendente, ha aggiunto riferimento reparto esistente e salvato nuovo dipendente al database. Dov'è il problema? Il problema è che AddObject non aggiunge solo il dipendente ma l'intero grafico dell'oggetto. È così che funziona EF: non è possibile avere un oggetto grafico dove una parte degli oggetti è connessa al contesto e parte del no. AddObject aggiunge ogni oggetto nel grafico come uno nuovo (nuovo = inserimento nel database). Pertanto, è necessario modificare la sequenza delle operazioni o correggere manualmente lo stato delle entità in modo che il contesto sappia che il reparto esiste già.

Prima soluzione - utilizzare lo stesso contesto per il reparto di carico di lavoro e dipendente risparmio:

using (var context = new YourContext()) 
{ 
    var employee = new Employee(); 
    ... 
    context.Employees.AddObject(employee); 

    employee.Department = context.Departments.Single(d => d.Id == departmentId); 
    context.SaveChanges(); 
} 

Seconda soluzione - collegare le entità al contesto separatamente e dopo che fanno riferimento tra entità:

var employee = new Employee(); 
... 

var department = GetDepartmentFromSomewhere(departmentId); 

using (var context = new YourContext()) 
{ 
    context.Employees.AddObject(employee); 
    context.Departments.Attach(department); 
    employee.Department = department; 

    context.SaveChanges(); 
} 

Terzo soluzione - stato corretto del dipartimento manualmente in modo che il contesto non lo inserisca nuovamente:

var employee = new Employee(); 
employee.Department = GetDepartmentFromSomewhere(departmentId); 

... 

using (var context = new YourContext()) 
{ 
    context.Employees.AddObject(employee); 
    context.ObjectStateManager.ChangeObjectState(employee.Department, 
               EntityState.Unchanged); 
    context.SaveChanges(); 
} 
+1

Grazie mille signore. Ho solo una parola per te, ECCEZIONALE. –

+0

Uso la classe derivata da 'DbContext' e il seguente ha lo stesso effetto di Terza soluzione per' DbContext' 'context.Entry (employee.Department) .State = EntityState.Unchanged;' – twnaing

+3

Nella terza soluzione, cosa succede se l'oggetto del Dipartimento ha ancora un'altra relazione? AddObject contrassegna tutto ciò anche come aggiunto? Come puoi ricorsivamente riportare le cose a invariato? – Bobson

0

Quando si imposta il reparto per dipendente - penso che si dovrebbe verificare il reparto è stato recuperato dal db ed è attaccato entità.
Inoltre, è possibile inserire l'id di privtment (la proprietà della chiave esterna) anziché impostare la proprietà di navigazione del dipartimento.

1

Vorrei aggiungere una quarta soluzione oltre alle 3 soluzioni già fornite nell'enorme risposta di Ladislav. Di fatto è una versione dettagliata della breve risposta di Naor. Sto lavorando con la versione Entity Framework 6.


assegnare il deparment id al dipendente al posto di oggetto reparto

tendo ad avere una proprietà "valore chiave straniero" in aggiunta al proprietà di navigazione nelle mie classi di modelli.

Così sulla classe Employee Ho una proprietà Department ed anche un DepartmentId di tipo int (rendono il int nullable se possibile che un Employee non ha Department):

public class Employee 
{ 
    public int Id { get; set; } 

    public String EmployeeName { get; set; } 


    #region FK properties 

    public Department Department { get; set; } 

    public int? DepartmentId { get; set; } 

    #endregion 
} 

Vuoi poteva fare ora è basta impostare la DepartmentId: Così, invece di:

employee.Department = departmentObject; 

appena impostato:

employee.DepartmentId = departmentObject.Id; 

o

employee.DepartmentId = departmentid 

Ora quando si chiama SaveChanges sul dipendente aggiunta, solo il dipendente viene salvato e non viene creato nessun nuovo reparto. Ma il riferimento da Employee a Department è impostato correttamente a causa dell'ID reparto assegnato.


Maggiori informazioni

Io di solito avrei accedere all'oggetto della classe EmployeeDepartment solo quando la lettura/dipendenti di lavorazione. Durante la creazione o l'aggiornamento dei dipendenti, vorrei utilizzare la proprietàdella classe Employee da assegnare a.

non assegnare alla Department proprietà del Employee ha un rovescio della medaglia: si potrebbe fare il debug più difficile, perché prima di chiamare SaveChanges e rileggendo i dipendenti non sarebbe possibile vedere o utilizzare l'oggetto della EmployeeDepartment.


fissaggio informazioni Stato entità EF6

Questo si riferisce al numero Ladislavs soluzione 3.

Con EF6 è fatto in questo modo:

_context.Entry(employee.Department).State = EntityState.Unchanged; 
Problemi correlati