Ho la seguente entità:
public class Employee
{
public Guid Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
public string State { get; set; }
}
E usando un'API fluente ho configurato l'entità posseduta come segue:
private void ConfigureEmployee(EntityTypeBuilder<Employee> builder)
{
builder.OwnsOne(x => x.Address, w =>
{
w.Property(x => x.City).HasMaxLength(100);
w.Property(x => x.State).HasMaxLength(100);
});
}
E quando provo a eliminare l'entità Employee:
var employee = dbContext.Employees.AsNoTracking().FirstOrDefault();
dbContext.Entry(employee).State = EntityState.Deleted;
dbContext.SaveChanges();
Ho ottenuto la seguente eccezione:
L'entità di tipo "Dipendente" condivide la tabella "Dipendenti" con entità di tipo "Dipendente.Indirizzo # indirizzo", ma non esiste un'entità di questo tipo con lo stesso valore chiave "{Id: 1ad382d7-4064-49a3-87ee -633578175247} "che è stato contrassegnato come" Eliminato ".
Ho provato la soluzione alternativa qui specificata ma non ha funzionato.
Sto usando EntityFrameworkCore v2.2.4
Il problema che stai affrontando è dovuto al modo in cui carichi l'entità. Quando lo fai:
var employee = dbContext.Employees.AsNoTracking().FirstOrDefault();
In pratica stai dicendo a EF: carica questo Employee
per me, ma dimenticalo. Trattalo come se non lo avessi mai caricato in primo luogo.
Successivamente, si desidera eliminarlo. Sai che non viene monitorato da DbContext
quindi fai:
dbContext.Entry(employee).State = EntityState.Deleted;
Questa è la "chiave" del problema. Questa riga dice a DbContext
: Ehi, ti preghiamo di iniziare a tracciare questa entità e contrassegnarla come da eliminare.
Il problema: l'entità Employee
possiede un indirizzo ma DbContext
non è a conoscenza del fatto che si desidera eliminarlo.
Il messaggio di errore che ricevi offre molte informazioni sull'errore reale, ma potrebbe non essere così chiaro a prima vista:
L'entità di tipo "Dipendente" condivide la tabella "Dipendenti" con entità di tipo "Dipendente.Indirizzo # indirizzo", ma non esiste un'entità di questo tipo con lo stesso valore chiave "{Id: 1ad382d7-4064-49a3-87ee -633578175247} "che è stato contrassegnato come" Eliminato ".
Questo sta dicendo: L'entità Employee
con ID 4 è contrassegnata come Deleted
ma ha anche un'entità di tipo Address
che non è stata aggiunta per essere eliminata . Anche se non hai dichiarato l' Address
come DbSet
nel tuo contesto, è ancora un'entità reale per quanto riguarda EF.
Per risolverlo mantenendo lo stesso codice che hai, devi anche aggiungere l' Address
da eliminare:
context.Entry(employee.Address).State = EntityState.Deleted;
Ma:
Non sono sicuro se questo è solo un esempio o se è il tuo vero codice. Ma personalmente (e ne vedo molti anche contrari) cerco di evitare il più possibile la manipolazione manuale degli stati delle entità. Questo può diventare brutto abbastanza rapidamente e produrre, poiché hai già sperimentato risultati non così ovvi. Invece, se si dispone di un DbContext
che si carica l'entità che si desidera eliminare, è possibile evitare di interferire con stati e problemi semplicemente modificando il codice in questo:
var employee = dbContext.Employees.First();
// .Remove will also mark the related entities to be deleted
// If Employee is not tracked, it will also start tracking it
// So, it's not necessary to do .Attach()
dbContext.Remove(employee);
dbContext.SaveChanges();
Questo funzionerà e l'entità verrà eliminata come previsto. Ovviamente, se il tuo codice non è quello e tu, in effetti, stai lavorando con entità in uno scenario disconnesso, allora devi impostarlo manualmente per essere eliminato come ho mostrato sopra.
Modificare:
Come sottolineato nei commenti di @IvanStoev, il metodo Remove
è ciò che può effettivamente risolvere il comportamento che stai affrontando. Il metodo Remove
contrassegna l'entità stessa oltre a quelle correlate come Deleted
e, se non precedentemente monitorate, inizierà anche a tracciarle. Dai documenti: (enfasi da me)
Se l'entità è già tracciata nello stato Aggiunto, il contesto smetterà di tracciare l'entità (anziché contrassegnarla come Eliminata) poiché l'entità è stata precedentemente aggiunta al contesto e non esiste nel database.
Qualsiasi altra entità raggiungibile che non è già stata tracciata verrà tracciata nello stesso modo in cui verrebbe se si chiamasse Attach (Object) prima di chiamare questo metodo. Ciò consente di applicare qualsiasi azione a cascata quando viene chiamato SaveChanges ().
Devi usare l'eliminazione a cascata come di seguito:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasOptional<Standard>(s => s.Address)
.WithMany()
.WillCascadeOnDelete(false);
}