Questa domanda è comune, ma non riesco ancora a capire come aggiornare correttamente l'entità correlata?
Ho il codice seguente:
public async Task<bool> UpdateStepAssignedToLevelAsync(Step step, Guid levelId, int priority = -1)
{
var item = await this._context.StepLevels
.Include(sl => sl.Step)
.FirstOrDefaultAsync(x => x.StepId == step.Id && x.LevelId == levelId);
if (item == null)
{
return false;
}
//this._context.Entry(item).State = EntityState.Detached;
if (priority > -1)
{
item.Priority = priority;
}
item.Step = step;
//this._context.StepLevels.Update(item);
var rows = await this._context.SaveChangesAsync();
return rows > 0;
}
Quando viene eseguito ho ricevuto il seguente errore:
InvalidOperationException: The instance of entity type 'Step' cannot be tracked because another instance with the key value '{Id: 35290c18-5b0a-46a5-8f59-8888cf548df5}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
Come ho capito, l'entità viene monitorata dalla richiesta di selezione all'avvio del metodo. Va bene, ma quando sto staccando l'entità e chiamando il metodo di aggiornamento (vedere le righe commentate), l'entità Step non viene modificata. Ma StepLevel lo fa: la priorità sta cambiando. Quando sto provando a chiamare solo Aggiorna l'EF prova ad inserire il nuovo Step invece di aggiornare quello esistente.
Quindi, potresti per favore consigliarmi, qual è la migliore pratica qui?
Grazie mille in anticipo!
Innanzitutto, se si scollega un'entità non si scollegano le entità correlate, quindi l' item
scollegamento non scollega l' item.Step
recuperato con .Include(sl => sl.Step)
.
In secondo luogo, poiché non si desidera modificare l' item.Step
, ma per aggiornare l'entità Step
esistente ( x.StepId == step.Id
), e si sa che il contesto sta monitorando (contiene) l'entità Step
corrispondente caricata da Nel database, dovresti utilizzare la procedura per aggiornare un'entità db da un'entità distaccata tramite Entry(...).CurrentValues.SetValues
Metodo Entry(...).CurrentValues.SetValues
.
Quindi rimuovi
item.Step = step;
e utilizzare invece quanto segue:
this._context.Entry(item.Step).CurrentValues.SetValues(step);
Ultima nota Quando si lavora con entità collegate, non è necessario (non dovrebbe) utilizzare il metodo di Update
. Il tracker delle modifiche rileverà automaticamente i valori delle proprietà modificate se una qualsiasi delle entità viene monitorata.
Il contesto sta monitorando l'entità Step corrispondente caricata dal DB per tale motivo sta generando questo errore. Puoi aggiornare ogni proprietà Step -
public bool UpdateStepAssignedToLevelAsync(Step step, int levelId)
{
using(var context = new StackOverFlowDbContext())
{
var item = context.StepLevels
.Include(sl => sl.Step)
.FirstOrDefault(x => x.Id == step.Id && x.Id == levelId);
if (item == null)
{
return false;
}
// Updating Name property
item.Step.Name = step.Name;
// Other properties can be upadated
var rows = context.SaveChanges();
return rows > 0;
}
}