Ho i seguenti due set di entità che rappresentano Dept & Emp: -
public partial class Dept
{
public Dept()
{
this.Emps = new HashSet<Emp>();
}
public int DeptID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Emp> Emps { get; set; }
}
public partial class Emp
{
public int EmpID { get; set; }
public string Fname { get; set; }
public string Lname { get; set; }
public int DeptID { get; set; }
public virtual Dept Dept { get; set; }
}
Ora ho scritto questo metodo di prova, che cercherà di eliminare un reparto a cui è assegnato un Emp, come segue:
public ActionResult Test()
{
Dept d = db.Depts.SingleOrDefault(a=>a.id ==1);
Emp e = db.Emps.SingleOrDefault(a => a.id == 100);
db.Entry(d).State = EntityState.Deleted;
db.Emps.Remove(e);
db.SaveChanges();
return Content("done");
}
Ho pensato che verrà sollevata un'eccezione quando si chiama questo metodo di azione, dal momento che il Dept
con id=1
ha già un emp con id = 100. Ma quello che è successo è che EF ha rimosso prima i emp, poi i dept. Come risultato finale il metodo di azione sopra, cancellato sia il dept con id = 1 che emp con id = 100 .. quindi puoi consigliarti su questo per favore? Tenendo presente che se provo a cancellare il Dept solo come segue:
public ActionResult Test()
{
Dept d = db.Depts.SingleOrDefault(a=>a.id ==1);
//Emp e = db.Emps.SingleOrDefault(a => a.id == 100);
db.Entry(d).State = EntityState.Deleted;
//db.Emps.Remove(e);
db.SaveChanges();
return Content("done");
}
Otterrò la seguente eccezione: -
L'istruzione DELETE è in conflitto con il vincolo REFERENCE \ "FK_Emp_ToTable \". Il conflitto si è verificato nel database \ "C: \ USERS \ ... \ DOCUMENTS \ VISUAL STUDIO 2013 \ PROJECTS \ WEBAPPLICATION19 \ WEBAPPLICATION19 \ APP_DATA \ DATABASE1.MDF \", tabella \ "dbo.Emp \", colonna 'DeptID'. \ r \ nLa dichiarazione è stata chiusa. "}
Quindi qualcuno può dare consigli su come EF sta implementando questi scenari?
MODIFICARE
controllo il sql profiler per il mio metodo di azione e ho notato le seguenti 2 cancellazioni di sql: -
exec sp_executesql N'delete [dbo].[Emp]
where ([EmpID] = @0)',N'@0 int',@0=100
exec sp_executesql N'delete [dbo].[Dept]
where ([DeptID] = @0)',N'@0 int',@0=1
così ha cancellato prima il emp poi il dept, quindi come EF determina l'ordine, hai detto che è abbastanza intelligente da sapere, ma cosa governa questo comportamento?
Hai provato a eliminare un Dept
cui è stata assegnata una serie di Emp
.
Si è verificata la seguente eccezione
L'istruzione DELETE è in conflitto con il vincolo REFERENCE
Ciò significa che c'è un vincolo alla relazione Dept - Emp. La mia ipotesi è che sia un rapporto uno a molti, con un reparto che è facoltativo per Emp.
Posso dire che è facoltativo perché la chiave DeptID
è un DeptID
Nullable<int>
.
Quando si tenta di eliminare un Dept
, si ottiene un'eccezione perché in Emp
viene fatto riferimento a dept.
Nel primo metodo di azione eliminato dalla chiave primaria
Dept d = db.Depts.SingleOrDefault(a=>a.id ==1);
Emp e = db.Emps.SingleOrDefault(a => a.id == 100);
E poi usato db.Emps.Remove(e);
per contrassegnare la relazione tra come cancellato. Se la relazione era facoltativa, Emp
sarebbe impostato su Null utilizzando solo un SQL Update.
Nel tuo caso vedo due SQL Delete statements
chiamate La relazione è quindi identificativa .
Quando una chiave primaria dell'entità principale fa anche parte della chiave primaria dell'entità dipendente, la relazione è una relazione identificativa. In una relazione identificativa l'entità dipendente non può esistere senza l'entità principale. Questo vincolo provoca i seguenti comportamenti in una relazione di identificazione:
L'eliminazione dell'oggetto principale cancella anche l'oggetto dipendente. Questo è lo stesso comportamento che specifica nel modello per la relazione.
La rimozione della relazione cancella l'oggetto dipendente. La chiamata del metodo Remove su EntityCollection contrassegna sia la relazione che l'oggetto dipendente per l'eliminazione.