Leggere in inglese

Condividi tramite


Eliminazione a catena

Entity Framework Core (EF Core) rappresenta le relazioni usando chiavi esterne. Un'entità con una chiave esterna è l'entità figlio o dipendente nella relazione. Il valore della chiave esterna dell'entità deve corrispondere al valore della chiave primaria (o a un valore di chiave alternativo) dell'entità principale/padre correlata.

Se l'entità principale/padre viene eliminata, i valori di chiave esterna dei dipendenti/figli non corrisponderanno più alla chiave primaria o alternativa di qualsiasi entità o padre. Si tratta di uno stato non valido e causerà una violazione del vincolo referenziale nella maggior parte dei database.

Esistono due opzioni per evitare questa violazione del vincolo referenziale:

  1. Impostare i valori FK su Null
  2. Eliminare anche le entità dipendenti/figlio

La prima opzione è valida solo per le relazioni facoltative in cui la proprietà della chiave esterna (e la colonna di database a cui è mappato) deve essere nullable.

La seconda opzione è valida per qualsiasi tipo di relazione ed è nota come "eliminazione a catena".

Suggerimento

Questo documento descrive le eliminazioni a catena (ed eliminazione di orfani) dal punto di vista dell'aggiornamento del database. Usa molto i concetti introdotti in Rilevamento modifiche in EF Core e modifica di chiavi esterne e spostamenti. Assicurarsi di comprendere appieno questi concetti prima di affrontare il materiale qui.

Suggerimento

È possibile eseguire ed eseguire il debug in tutto il codice di questo documento scaricando il codice di esempio da GitHub.

Quando si verificano comportamenti a catena

Le eliminazioni a catena sono necessarie quando un'entità dipendente/figlio non può più essere associata all'entità principale/padre corrente. Ciò può verificarsi perché l'entità o l'elemento padre viene eliminato oppure può verificarsi quando l'entità o l'elemento padre esiste ancora, ma il dipendente/figlio non è più associato.

Eliminazione di un'entità/padre

Si consideri questo modello semplice dove Blog è l'entità/padre in una relazione con Post, che è il dipendente/figlio. Post.BlogId è una proprietà di chiave esterna, il cui valore deve corrispondere alla Blog.Id chiave primaria del blog a cui appartiene il post.

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

    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();
}

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

    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

Per convenzione, questa relazione viene configurata come obbligatoria, poiché la proprietà della Post.BlogId chiave esterna non è nullable. Le relazioni necessarie sono configurate per l'uso di eliminazioni a catena per impostazione predefinita. Per altre informazioni sulla modellazione delle relazioni, vedere Relazioni .

Quando si elimina un blog, tutti i post vengono eliminati a catena. Ad esempio:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

context.Remove(blog);

context.SaveChanges();

SaveChanges genera il codice SQL seguente, usando SQL Server come esempio:

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Severing a relationship (Severing a relationship)

Invece di eliminare il blog, è possibile invece severarsi la relazione tra ogni post e il relativo blog. Questa operazione può essere eseguita impostando la navigazione Post.Blog di riferimento su Null per ogni post:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

context.SaveChanges();

La relazione può anche essere interrotta rimuovendo ogni post dal riquadro di spostamento della Blog.Posts raccolta:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

blog.Posts.Clear();

context.SaveChanges();

In entrambi i casi il risultato è lo stesso: il blog non viene eliminato, ma i post che non sono più associati ad alcun blog vengono eliminati:

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

L'eliminazione di entità non più associate ad alcuna entità o dipendente è nota come "eliminazione di orfani".

Suggerimento

L'eliminazione a catena e l'eliminazione degli orfani sono strettamente correlate. Entrambi comportano l'eliminazione di entità dipendenti/figlio quando la relazione con l'entità principale/padre richiesta viene interrotta. Per l'eliminazione a catena, questo severing si verifica perché l'entità o l'elemento padre viene eliminato. Per gli orfani, l'entità principale/padre esiste ancora, ma non è più correlata alle entità dipendenti/figlio.

Dove si verificano comportamenti a catena

I comportamenti a catena possono essere applicati a:

  • Entità rilevate dall'oggetto corrente DbContext
  • Entità nel database che non sono state caricate nel contesto

Eliminazione a catena di entità rilevate

EF Core applica sempre comportamenti di propagazione configurati alle entità rilevate. Ciò significa che se l'applicazione carica tutte le entità dipendenti/figlio rilevanti in DbContext, come illustrato negli esempi precedenti, i comportamenti a catena verranno applicati correttamente indipendentemente dalla modalità di configurazione del database.

Suggerimento

La tempistica esatta di quando si verificano comportamenti a catena per tenere traccia delle entità può essere controllata usando ChangeTracker.CascadeDeleteTiming e ChangeTracker.DeleteOrphansTiming. Per altre informazioni, vedere Modifica di chiavi esterne e spostamenti .

Eliminazione a catena nel database

Molti sistemi di database offrono anche comportamenti a catena attivati quando un'entità viene eliminata nel database. EF Core configura questi comportamenti in base al comportamento di eliminazione a catena nel modello EF Core quando viene creato un database usando EnsureCreated o migrazioni di EF Core. Ad esempio, usando il modello precedente, viene creata la tabella seguente per i post quando si usa SQL Server:

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    [BlogId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]) ON DELETE CASCADE
);

Si noti che il vincolo di chiave esterna che definisce la relazione tra blog e post è configurato con ON DELETE CASCADE.

Se si sa che il database è configurato in questo modo, è possibile eliminare un blog senza prima caricare post e il database si occupa dell'eliminazione di tutti i post correlati a tale blog. Ad esempio:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).First();

context.Remove(blog);

context.SaveChanges();

Si noti che non esiste alcun post Include , quindi non vengono caricati. SaveChanges in questo caso eliminerà solo il blog, poiché questa è l'unica entità monitorata:

-- Executed DbCommand (6ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

Ciò comporta un'eccezione se il vincolo di chiave esterna nel database non è configurato per le eliminazioni a catena. Tuttavia, in questo caso i post vengono eliminati dal database perché è stato configurato con ON DELETE CASCADE quando è stato creato.

Nota

I database in genere non dispongono di alcun modo per eliminare automaticamente gli orfani. Ciò è dovuto al fatto che, mentre EF Core rappresenta le relazioni tramite spostamenti e chiavi esterne, i database hanno solo chiavi esterne e nessuna navigazione. Ciò significa che in genere non è possibile eseguire uno severing di una relazione senza caricare entrambi i lati in DbContext.

Nota

Il database in memoria di EF Core attualmente non supporta le eliminazioni a catena nel database.

Avviso

Non configurare l'eliminazione a catena nel database durante l'eliminazione temporanea delle entità. Ciò può causare l'eliminazione accidentale delle entità anziché l'eliminazione temporanea.

Limitazioni a catena del database

Alcuni database, in particolare SQL Server, presentano limitazioni sui comportamenti a catena che formano cicli. Si consideri ad esempio il modello seguente:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();

    public int OwnerId { get; set; }
    public Person Owner { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }

    public int AuthorId { get; set; }
    public Person Author { get; set; }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();

    public Blog OwnedBlog { get; set; }
}

Questo modello ha tre relazioni, tutte necessarie e quindi configurate per l'eliminazione a catena per convenzione:

  • L'eliminazione di un blog eliminerà tutti i post correlati
  • L'eliminazione dell'autore dei post causerà l'eliminazione a catena dei post creati
  • L'eliminazione del proprietario di un blog causerà l'eliminazione a catena del blog

Questo è tutto ragionevole (se un po ' draconian nei criteri di gestione del blog!) ma il tentativo di creare un database di SQL Server con questi cascades configurati comporta l'eccezione seguente:

Microsoft.Data.SqlClient.SqlException (0x80131904): l'introduzione del vincolo FOREIGN KEY 'FK_Posts_Person_AuthorId' nella tabella 'Post' può causare cicli o più percorsi a catena. Specificare ON DELETE NO ACTION o ON UPDATE NO ACTION oppure modificare gli altri vincoli FOREIGN KEY.

Esistono due modi per gestire questa situazione:

  1. Modificare una o più relazioni in modo che non vengano eliminate a catena.
  2. Configurare il database senza una o più di queste eliminazioni a catena, quindi assicurarsi che tutte le entità dipendenti vengano caricate in modo che EF Core possa eseguire il comportamento a catena.

Prendendo il primo approccio con l'esempio, è possibile rendere facoltativa la relazione post-blog assegnando una proprietà di chiave esterna nullable:

public int? BlogId { get; set; }

Una relazione facoltativa consente l'esistenza del post senza un blog, il che significa che l'eliminazione a catena non verrà più configurata per impostazione predefinita. Ciò significa che non è più presente un ciclo nelle azioni a catena e il database può essere creato senza errori in SQL Server.

Prendendo invece il secondo approccio, è possibile mantenere la relazione del proprietario del blog obbligatoria e configurata per l'eliminazione a catena, ma rendere questa configurazione applicabile solo alle entità rilevate, non al database:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

Ora cosa succede se carichiamo sia una persona che il blog di cui sono proprietari, quindi eliminiamo la persona?

using var context = new BlogsContext();

var owner = context.People.Single(e => e.Name == "ajcvickers");
var blog = context.Blogs.Single(e => e.Owner == owner);

context.Remove(owner);

context.SaveChanges();

EF Core scadrà l'eliminazione del proprietario in modo che anche il blog venga eliminato:

-- Executed DbCommand (8ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [People]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Tuttavia, se il blog non viene caricato quando il proprietario viene eliminato:

using var context = new BlogsContext();

var owner = context.People.Single(e => e.Name == "ajcvickers");

context.Remove(owner);

context.SaveChanges();

Verrà quindi generata un'eccezione a causa della violazione del vincolo di chiave esterna nel database:

Microsoft.Data.SqlClient.SqlException: istruzione DELETE in conflitto con il vincolo REFERENCE "FK_Blogs_Persone_OwnerId". Il conflitto si è verificato nel database "Scratch", tabella "dbo. Blogs", colonna 'OwnerId'. L'istruzione è stata interrotta.

Valori Null a cascata

Le relazioni facoltative hanno proprietà di chiave esterna nullable mappate alle colonne di database nullable. Ciò significa che il valore della chiave esterna può essere impostato su Null quando l'entità principale/padre corrente viene eliminata o viene interrotta dal dipendente/figlio.

Esaminiamo di nuovo gli esempi di Quando si verificano comportamenti a catena, ma questa volta con una relazione facoltativa rappresentata da una proprietà di chiave esterna nullable Post.BlogId :

public int? BlogId { get; set; }

Questa proprietà di chiave esterna verrà impostata su Null per ogni post quando viene eliminato il blog correlato. Ad esempio, questo codice, uguale a prima:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

context.Remove(blog);

context.SaveChanges();

Verranno ora restituiti gli aggiornamenti del database seguenti quando viene chiamato SaveChanges:

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (1ms) [Parameters=[@p2='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p2;
SELECT @@ROWCOUNT;

Analogamente, se la relazione viene interrotta usando uno degli esempi precedenti:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

context.SaveChanges();

Oppure:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

blog.Posts.Clear();

context.SaveChanges();

I post vengono quindi aggiornati con valori di chiave esterna Null quando viene chiamato SaveChanges:

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Per altre informazioni su come EF Core gestisce chiavi esterne e spostamenti man mano che vengono modificati i relativi valori, vedere Modifica di chiavi esterne e spostamenti.

Nota

La correzione di relazioni come questa è il comportamento predefinito di Entity Framework dalla prima versione del 2008. Prima di EF Core non aveva un nome e non era possibile modificare. Ora è noto come ClientSetNull descritto nella sezione successiva.

I database possono anche essere configurati in modo che i valori Null a catena siano simili a questo quando un'entità o un elemento padre in una relazione facoltativa viene eliminata. Tuttavia, questo comportamento è molto meno comune rispetto all'uso di eliminazioni a catena nel database. L'uso delle eliminazioni a catena e dei valori Null a catena nel database contemporaneamente comporterà quasi sempre cicli di relazione quando si usa SQL Server. Per altre informazioni sulla configurazione di valori Null a catena, vedere la sezione successiva.

Configurazione dei comportamenti a catena

Suggerimento

Assicurarsi di leggere le sezioni precedenti prima di venire qui. È probabile che le opzioni di configurazione non abbiano senso se il materiale precedente non è compreso.

I comportamenti a catena vengono configurati per relazione usando il OnDelete metodo in OnModelCreating. Ad esempio:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

Per altre informazioni sulla configurazione delle relazioni tra tipi di entità, vedere Relazioni .

OnDeleteaccetta un valore dall'enumerazione, ammettendo confusione. DeleteBehavior Questa enumerazione definisce sia il comportamento di EF Core nelle entità rilevate che la configurazione dell'eliminazione a catena nel database quando EF viene usato per creare lo schema.

Impatto sullo schema del database

Nella tabella seguente viene illustrato il risultato di ogni OnDelete valore nel vincolo di chiave esterna creato dalle migrazioni di EF Core o EnsureCreated.

DeleteBehavior Impatto sullo schema del database
Cascade ON DELETE CASCADE
Limita ON DELETE RESTRICT
NoAction database predefinito
SetNull ON DELETE edizione Standard T NULL
ClientSetNull database predefinito
ClientCascade database predefinito
ClientNoAction database predefinito

I comportamenti di ON DELETE NO ACTION (impostazione predefinita del database) e ON DELETE RESTRICT nei database relazionali sono in genere identici o molto simili. Nonostante ciò che NO ACTION può implicare, entrambe queste opzioni comportano l'applicazione di vincoli referenziale. La differenza, quando ne esiste una, è quando il database controlla i vincoli. Controllare la documentazione del database per individuare le differenze specifiche tra ON DELETE NO ACTION e ON DELETE RESTRICT nel sistema di database.

SQL Server non supporta ON DELETE RESTRICT, quindi ON DELETE NO ACTION viene usato.

Gli unici valori che causeranno comportamenti a catena nel database sono Cascade e SetNull. Tutti gli altri valori configureranno il database in modo che non vengano apportate modifiche a catena.

Impatto sul comportamento di SaveChanges

Le tabelle nelle sezioni seguenti illustrano cosa accade alle entità dipendenti/figlio quando l'entità principale/padre viene eliminata o la relazione con le entità dipendenti/figlio viene interrotta. Ogni tabella copre uno dei seguenti elementi:

  • Relazioni facoltative (FK nullable) e obbligatorie (FK non nullable)
  • Quando dipendenti/figli vengono caricati e rilevati da DbContext e quando sono presenti solo nel database

Relazione obbligatoria con dipendenti/figli caricati

DeleteBehavior In caso di eliminazione di entità/padre In caso di severing da principal/parent
Cascade Dipendenti eliminati da EF Core Dipendenti eliminati da EF Core
Limita InvalidOperationException InvalidOperationException
NoAction InvalidOperationException InvalidOperationException
SetNull SqlException durante la creazione di un database SqlException durante la creazione di un database
ClientSetNull InvalidOperationException InvalidOperationException
ClientCascade Dipendenti eliminati da EF Core Dipendenti eliminati da EF Core
ClientNoAction DbUpdateException InvalidOperationException

Note:

  • L'impostazione predefinita per le relazioni necessarie, come in questo caso, è Cascade.
  • L'uso di qualsiasi elemento diverso dall'eliminazione a catena per le relazioni necessarie genererà un'eccezione quando viene chiamato SaveChanges.
    • In genere, si tratta di un oggetto InvalidOperationException di EF Core perché lo stato non valido viene rilevato nei figli/dipendenti caricati.
    • ClientNoAction forza EF Core a non controllare le correzioni dipendenti prima di inviarle al database, quindi in questo caso il database genera un'eccezione, che viene quindi sottoposta a wrapping in un DbUpdateException oggetto da SaveChanges.
    • SetNull viene rifiutato quando si crea il database perché la colonna chiave esterna non è nullable.
  • Poiché i dipendenti/figli vengono caricati, vengono sempre eliminati da EF Core e non vengono mai lasciati per eliminare il database.

Relazione obbligatoria con dipendenti/figli non caricati

DeleteBehavior In caso di eliminazione di entità/padre In caso di severing da principal/parent
Cascade Dipendenti eliminati dal database N/D
Limita DbUpdateException N/D
NoAction DbUpdateException N/D
SetNull SqlException durante la creazione di un database N/D
ClientSetNull DbUpdateException N/D
ClientCascade DbUpdateException N/D
ClientNoAction DbUpdateException N/D

Note:

  • Se una relazione non è valida in questo caso, i dipendenti o i figli non vengono caricati.
  • L'impostazione predefinita per le relazioni necessarie, come in questo caso, è Cascade.
  • L'uso di qualsiasi elemento diverso dall'eliminazione a catena per le relazioni necessarie genererà un'eccezione quando viene chiamato SaveChanges.
    • In genere, si tratta di perché DbUpdateException i dipendenti/figli non vengono caricati e quindi lo stato non valido può essere rilevato solo dal database. SaveChanges esegue quindi il wrapping dell'eccezione del database in un oggetto DbUpdateException.
    • SetNull viene rifiutato quando si crea il database perché la colonna chiave esterna non è nullable.

Relazione facoltativa con dipendenti/figli caricati

DeleteBehavior In caso di eliminazione di entità/padre In caso di severing da principal/parent
Cascade Dipendenti eliminati da EF Core Dipendenti eliminati da EF Core
Limita FK dipendenti impostati su Null da EF Core FK dipendenti impostati su Null da EF Core
NoAction FK dipendenti impostati su Null da EF Core FK dipendenti impostati su Null da EF Core
SetNull FK dipendenti impostati su Null da EF Core FK dipendenti impostati su Null da EF Core
ClientSetNull FK dipendenti impostati su Null da EF Core FK dipendenti impostati su Null da EF Core
ClientCascade Dipendenti eliminati da EF Core Dipendenti eliminati da EF Core
ClientNoAction DbUpdateException FK dipendenti impostati su Null da EF Core

Note:

  • Il valore predefinito per le relazioni facoltative come questo è ClientSetNull.
  • I dipendenti/figli non vengono mai eliminati a meno che Cascade non siano configurati o ClientCascade .
  • Tutti gli altri valori determinano l'impostazione di FK dipendenti su Null da EF Core...
    • ... tranne ClientNoAction che indica a EF Core di non toccare le chiavi esterne di dipendenti/figli quando l'entità o l'elemento padre viene eliminato. Il database genera quindi un'eccezione, di cui viene eseguito il wrapping come oggetto DbUpdateException da SaveChanges.

Relazione facoltativa con dipendenti/figli non caricati

DeleteBehavior In caso di eliminazione di entità/padre In caso di severing da principal/parent
Cascade Dipendenti eliminati dal database N/D
Limita DbUpdateException N/D
NoAction DbUpdateException N/D
SetNull FK dipendenti impostati su Null per database N/D
ClientSetNull DbUpdateException N/D
ClientCascade DbUpdateException N/D
ClientNoAction DbUpdateException N/D

Note:

  • Se una relazione non è valida in questo caso, i dipendenti o i figli non vengono caricati.
  • Il valore predefinito per le relazioni facoltative come questo è ClientSetNull.
  • I dipendenti/figli devono essere caricati per evitare un'eccezione di database, a meno che il database non sia stato configurato per l'eliminazione a catena o i valori Null.