Sto cercando di aggiornare una chiave esterna utilizzando Entity Framework 7. Ma sta dando un errore: la proprietà 'Y' non è stata trovata nell'oggetto 'X'. Ho provato molte soluzioni diverse ma ancora non funzionante. Il codice di esempio:
class X
{
property Y {get; set;} -> property Y is a foreign key and also a complex type
}
Nella tabella 'X' abbiamo una colonna 'Y_ID' che è la chiave esterna.
Nota: voglio solo aggiornare la chiave esterna. Ad esempio, inizialmente la classe 'X' punta a 'NULL' , voglio aggiornare la classe 'X' per puntare a 'Y1'
Il codice Entity Framework 7:
var x = this.GetX();
this.mainContext.Xs.Attach(x);
var xEntry = this.mainContext.Entry(x);
xEntry.Property("Y").CurrentValue = "Y1"; // Error at this line
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
Errore dettagliato:
La proprietà 'Y' sul tipo di entità 'X' non è stata trovata. Assicurarsi che la proprietà esista e sia stata inclusa nel modello.
L'approccio suggerito da Fabien nel suo commento funziona bene. Ma il problema è che sappiamo solo quale proprietà aggiornare è in fase di runtime. Se utilizzo la reflection per raggiungere questo obiettivo, il problema è che il framework di entità considera l'oggetto come nuovo e prova a crearlo (INSERT) e poi lancia la violazione della chiave primaria (nessuna voce duplicata è consentita)
Quindi, c'è un modo in cui non posso ancora aggiornare una proprietà dell'oggetto che si comporta come una chiave esterna in EF? (Non conosco la proprietà esatta al momento della compilazione).
Se ottieni le entità "X" e "Y" dal tuo contesto, vengono automaticamente monitorate da ChangeTracker. Quindi se assegni la proprietà "Y" dell'oggetto "X" con un'istanza "Y" recuperata dal tuo contesto e chiami SaveChanges o SaveChangesAsync, EntityFramework farà automaticamente le cose per te.
var x = this.GetX();
x.Y = "Y1";
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
Per convenzione, la proprietà "Y" sull'oggetto "X" deve essere virtuale per indicare che si tratta di una chiave esterna.
Se capisco correttamente, si desidera aggiornare dinamicamente le proprietà dell'oggetto in fase di esecuzione, con valori che provengono da una API Web.
Come hai fatto tu, puoi allegare il tuo oggetto "X" all'istanza di contesto per iniziare il tracciamento dell'entità con EntityState.Unchanged e quindi contrassegnare ogni proprietà che deve essere aggiornata:
this.mainContext.Xs.Attach(x);
var entry = this.mainContext.entry(x);
entry.Property(p => p.Y).CurrentValue = "Y1";
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
Quando si collega un'entità, è possibile specificare GraphBehavior e indicare a EntityFramework se le proprietà di navigazione devono essere attraversate o meno.
Utilizzando il metodo DbSet.Update ():
this.mainContext.Xs.Update(x);
await this.mainContext.SaveChangesAsync().ConfigureAwait(false);
Inizia automaticamente il tracciamento dell'entità con lo stato EntityState.Modified, tutte le proprietà saranno contrassegnate come modificate. Si dovrebbe prestare attenzione quando si utilizza questo metodo, poiché tutte le proprietà verranno aggiornate, se alcune di esse non sono inizializzate nell'oggetto "X", si potrebbero perdere alcuni dati. Per evitare questo caso, devi sempre convalidare gli input.
Se vuoi mantenere i tuoi modelli di dominio disaccoppiati da qualsiasi ORM, allora dovresti pensare di separare i tipi di entità e i tipi di dominio. È possibile utilizzare un oggetto mapper come Automapper per mappare l'entità al tipo di dominio e viceversa. In questo modo separerai chiaramente ciò che fai al livello di accesso ai dati e al livello della logica aziendale.