Compartilhar via


Excluir em cascata

O EF Core (Entity Framework Core) representa as relações por meio de chaves estrangeiras. Uma entidade com uma chave estrangeira é a entidade filho ou dependente na relação. O valor da chave estrangeira dessa entidade precisa corresponder ao valor da chave primária (ou a um valor de chave alternativa) da entidade principal/pai relacionada.

Se a entidade principal/pai for excluída, os valores de chave estrangeira dos dependentes/filhos não corresponderão mais à chave primária ou alternativa de qualquer entidade principal/pai. Esse é um estado inválido, que causará uma violação de restrição referencial na maioria dos bancos de dados.

Há duas opções para evitar essa violação de restrição referencial:

  1. Definir os valores da FK como nulos
  2. Excluir também as entidades dependentes/filho

A primeira opção só é válida para relações opcionais em que a propriedade de chave estrangeira (e a coluna de banco de dados para a qual ela é mapeada) precisa ser anulável.

A segunda opção é válida para qualquer tipo de relação e é conhecida como “exclusão em cascata”.

Dica

Este documento descreve as exclusões em cascata (e a exclusão de órfãos) da perspectiva de atualização do banco de dados. Ele usa extensamente os conceitos introduzidos em Controle de alterações no EF Core e Como alterar chaves estrangeiras e navegações. Verifique se você entendeu por completo esses conceitos antes de lidar com o material apresentado aqui.

Dica

Você pode executar e depurar em todo o código neste documento baixando o código de exemplo do GitHub.

Quando ocorrem os comportamentos em cascata

As exclusões em cascata são necessárias quando uma entidade dependente/filho não pode mais ser associada à entidade principal/pai atual. Isso pode acontecer devido à entidade principal/pai ter sido excluído ou quando a entidade principal/pai ainda existe, mas o dependente/filho não está mais associado a ela.

Como excluir uma entidade principal/pai

Considere este modelo simples, em que Blog é a entidade principal/pai em uma relação com Post, que é o dependente/filho. Post.BlogId é uma propriedade de chave estrangeira, cujo valor precisa corresponder à chave primária Blog.Id do blog ao qual a postagem pertence.

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; }
}

Por convenção, essa relação é configurada como obrigatória, pois a propriedade de chave estrangeira Post.BlogId não é anulável. As relações obrigatórias são configuradas para usar as exclusões em cascata por padrão. Confira Relações para obter mais informações sobre as relações de modelagem.

Quando um blog é excluído, todas as postagens são excluídas em cascata. Por exemplo:

using var context = new BlogsContext();

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

context.Remove(blog);

context.SaveChanges();

SaveChanges gera o seguinte SQL, usando o SQL Server como exemplo:

-- 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;

Como cortar uma relação

Em vez de excluir o blog, podemos cortar a relação entre cada postagem e o blog. Faça isso definindo a navegação de referência Post.Blog como nula para cada postagem:

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();

A relação também pode ser cortada pela remoção de cada postagem da navegação da coleção Blog.Posts:

using var context = new BlogsContext();

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

blog.Posts.Clear();

context.SaveChanges();

Em ambos os casos, o resultado é o mesmo: o blog não é excluído, mas as postagens que não estão mais associadas a nenhum blog são excluídas:

-- 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;

A exclusão de entidades que não estão mais associadas a nenhuma entidade principal/nenhum dependente é conhecida como “exclusão de órfãos”.

Dica

A exclusão em cascata e a exclusão de órfãos estão intimamente relacionadas. Ambos resultam na exclusão de entidades dependentes/filho quando o relacionamento com a entidade de segurança/pai necessária é rompido. Para exclusão em cascata, essa separação ocorre porque a entidade de segurança/pai é excluída. Nos órfãos, a entidade principal/pai ainda existe, mas deixou de estar relacionada às entidades dependentes/filho.

Onde ocorrem os comportamentos em cascata

Os comportamentos em cascata podem ser aplicados aos seguintes:

  • Entidades rastreadas pelo DbContext atual
  • Entidades no banco de dados que não foram carregadas no contexto

Exclusão em cascata de entidades rastreadas

O EF Core sempre aplica os comportamentos em cascata configurados às entidades rastreadas. Isso significa que, se o aplicativo carregar todas as entidades dependentes/filho relevantes no DbContext, conforme mostrado nos exemplos acima, os comportamentos em cascata serão aplicados corretamente, seja qual for a configuração do banco de dados.

Dica

O tempo exato de quando os comportamentos em cascata ocorrem nas entidades rastreadas pode ser controlado por meio de ChangeTracker.CascadeDeleteTiming e ChangeTracker.DeleteOrphansTiming. Confira Como alterar chaves estrangeiras e navegações para obter mais informações.

Exclusão em cascata no banco de dados

Muitos sistemas de banco de dados também oferecem comportamentos em cascata que são disparados quando uma entidade é excluída do banco de dados. O EF Core configura esses comportamentos com base no comportamento da exclusão em cascata no modelo do EF Core quando um banco de dados é criado com EnsureCreated ou com as migrações do EF Core. Por exemplo, usando o modelo acima, a seguinte tabela é criada para postagens ao usar o 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
);

Observe que a restrição de chave estrangeira que define a relação entre os blogs e as postagens está configurada com ON DELETE CASCADE.

Se sabemos que o banco de dados está configurado dessa forma, podemos excluir um blog sem primeiro carregar as postagens e o banco de dados cuidará da exclusão de todas as postagens relacionadas ao blog. Por exemplo:

using var context = new BlogsContext();

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

context.Remove(blog);

context.SaveChanges();

Observe que não há nenhum Include para postagens, portanto, elas não foram carregadas. SaveChanges, nesse caso, excluirá apenas o blog, pois essa é a única entidade que está sendo rastreada:

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

Isso resultará em uma exceção se a restrição de chave estrangeira no banco de dados não estiver configurada para as exclusões em cascata. No entanto, nesse caso, as postagens são excluídas pelo banco de dados porque ele foi configurado com ON DELETE CASCADE no momento da criação.

Observação

Normalmente, os bancos de dados não apresentam nenhuma maneira de excluir os órfãos de modo automático. Isso ocorre porque, embora o EF Core represente as relações usando navegações, bem como chaves estrangeiras, os bancos de dados têm apenas chaves estrangeiras e nenhuma navegação. Isso significa que, em geral, não é possível cortar uma relação sem carregar ambos os lados no DbContext.

Observação

Atualmente, o banco de dados em memória do EF Core não dá suporte a exclusões em cascata no banco de dados.

Aviso

Não configure a exclusão em cascata no banco de dados ao excluir entidades temporariamente. Isso pode fazer com que as entidades sejam acidentalmente excluídas, em vez de excluídas de modo temporário.

Limitações da cascata no banco de dados

Alguns bancos de dados, principalmente, o SQL Server, têm limitações nos comportamentos em cascata que formam ciclos. Por exemplo, considere o seguinte modelo:

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; }
}

Esse modelo tem três relações, todas obrigatórias e, portanto, configuradas para a exclusão em cascata por convenção:

  • A exclusão de um blog vai disparar a exclusão em cascata de todas as postagens relacionadas
  • A exclusão do autor das postagens fará com que as postagens de autoria dele sejam excluídas em cascata
  • A exclusão do proprietário de um blog fará com que o blog seja excluído em cascata

Isso tudo é razoável (talvez excessivamente rigoroso nas políticas de gerenciamento de blog), mas a tentativa de criar um banco de dados do SQL Server com essas cascatas configuradas resulta na seguinte exceção:

Microsoft.Data.SqlClient.SqlException (0x80131904): A introdução da restrição FOREIGN KEY 'FK_Posts_Person_AuthorId' na tabela 'Posts' poderá causar ciclos ou vários caminhos em cascata. Especifique ON DELETE NO ACTION ou ON UPDATE NO ACTION, ou modifique outras restrições FOREIGN KEY.

Há duas maneiras de lidar com essa situação:

  1. Alterar uma ou mais das relações para não excluí-las em cascata.
  2. Configurar o banco de dados sem uma ou mais dessas exclusões em cascata e verificar se todas as entidades dependentes foram carregadas, para que o EF Core possa executar o comportamento em cascata.

Tomando a primeira abordagem com nosso exemplo, poderíamos tornar a relação pós-blog opcional, dando-lhe uma propriedade de chave estrangeira anulável:

public int? BlogId { get; set; }

Uma relação opcional permite que a postagem exista sem um blog, o que significa que a exclusão em cascata não será mais configurada por padrão. Isso significa que não há mais um ciclo nas ações em cascata e o banco de dados pode ser criado sem erros no SQL Server.

Usando a segunda abordagem, podemos manter a relação blog-proprietário obrigatória e configurada para exclusão em cascata, mas fazer com que essa configuração seja aplicada somente às entidades rastreadas, não ao banco de dados:

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

Agora, o que acontecerá se carregarmos uma pessoa e o blog pertencente a ela e excluirmos a pessoa?

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();

O EF Core vai disparar a exclusão em cascata do proprietário para que o blog também seja excluído:

-- 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;

No entanto, se o blog não for carregado quando o proprietário for excluído:

using var context = new BlogsContext();

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

context.Remove(owner);

context.SaveChanges();

Uma exceção será gerada devido à violação da restrição de chave estrangeira no banco de dados:

Microsoft.Data.SqlClient.SqlException: A instrução DELETE entrou em conflito com a restrição REFERENCE “FK_Blogs_People_OwnerId”. O conflito ocorreu no banco de dados “Scratch”, na tabela “dbo.Blogs”, na coluna ‘OwnerId’. A instrução foi finalizada.

Propagação de nulos em cascata

As relações opcionais têm as propriedades de chave estrangeira anuláveis mapeadas para colunas de banco de dados anuláveis. Isso significa que o valor de chave estrangeira pode ser definido como nulo quando a entidade principal/pai atual é excluída ou é cortada do dependente/filho.

Vamos dar mais uma olhada nos exemplos de Quando ocorrem os comportamentos em cascata, mas desta vez com uma relação opcional representada por uma propriedade de chave estrangeira Post.BlogId anulável:

public int? BlogId { get; set; }

Essa propriedade de chave estrangeira será definida como nula para cada postagem quando o blog relacionado for excluído. Por exemplo, este código, que é o mesmo de antes:

using var context = new BlogsContext();

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

context.Remove(blog);

context.SaveChanges();

Agora resultará nas seguintes atualizações de banco de dados quando SaveChanges for chamado:

-- 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;

Da mesma forma, se a relação for cortada por meio de um dos exemplos acima:

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();

Ou:

using var context = new BlogsContext();

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

blog.Posts.Clear();

context.SaveChanges();

As postagens serão atualizadas com valores de chave estrangeira nulos quando SaveChanges for chamado:

-- 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;

Confira Como alterar chaves estrangeiras e navegações para obter mais informações sobre como o EF Core gerencia as chaves estrangeiras e as navegações à medida que os respectivos valores são alterados.

Observação

A correção de relações como essa tem sido o comportamento padrão do Entity Framework desde a primeira versão em 2008. Antes do EF Core, ela não tinha nome e não era possível alterá-la. Ela passou a ser conhecida como ClientSetNull, conforme descrito na próxima seção.

Os bancos de dados também podem ser configurados para a propagação de nulos em cascata dessa forma quando uma entidade principal/pai em uma relação opcional é excluída. No entanto, isso é muito menos comum do que usar as exclusões em cascata no banco de dados. Usar as exclusões em cascata e a propagação de nulos em cascata no banco de dados simultaneamente resultará quase sempre em ciclos de relações durante o uso do SQL Server. Confira a próxima seção para obter mais informações sobre como configurar a propagação de nulos em cascata.

Como configurar comportamentos em cascata

Dica

Leia as seções acima antes de prosseguir. As opções de configuração provavelmente não farão sentido se o material anterior não for compreendido.

Os comportamentos em cascata são configurados por relação por meio do método OnDelete em OnModelCreating. Por exemplo:

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

Confira Relações para obter mais informações sobre como configurar relações entre tipos de entidades.

OnDelete aceita um valor da enumeração DeleteBehavior, reconhecidamente confusa. Essa enumeração define o comportamento do EF Core em entidades rastreadas e a configuração da exclusão em cascata no banco de dados quando o EF é usado para criar o esquema.

Impacto no esquema de banco de dados

A tabela a seguir mostra o resultado de cada valor OnDelete na restrição de chave estrangeira criada pelas migrações do EF Core ou por EnsureCreated.

DeleteBehavior Impacto no esquema de banco de dados
Cascata ON DELETE CASCADE
Restringir ON DELETE RESTRICT
NoAction padrão do banco de dados
SetNull ON DELETE SET NULL
ClientSetNull padrão do banco de dados
ClientCascade padrão do banco de dados
ClientNoAction padrão do banco de dados

Os comportamentos de ON DELETE NO ACTION (o padrão do banco de dados) e de ON DELETE RESTRICT em bancos de dados relacionais são normalmente idênticos ou muito semelhantes. Apesar do que NO ACTION possa implicar, essas duas opções fazem com que as restrições referenciais sejam impostas. A diferença, quando houver, é quando o banco de dados verifica as restrições. Verifique a documentação do banco de dados para conhecer as diferenças específicas entre ON DELETE NO ACTION e ON DELETE RESTRICT no sistema de banco de dados.

O SQL Server não dá suporte a ON DELETE RESTRICT, portanto, ON DELETE NO ACTION é usado.

Os únicos valores que causarão comportamentos em cascata no banco de dados são Cascade e SetNull. Todos os outros valores vão configurar o banco de dados para não propagar nenhuma alteração em cascata.

Impacto no comportamento de SaveChanges

As tabelas das seções a seguir abordam o que acontece com as entidades dependentes/filho quando a entidade principal/pai é excluída ou a relação delas com as entidades dependentes/filho é cortada. Cada tabela abrange um dos seguintes casos:

  • Relações opcionais (FK anulável) e obrigatórias (FK não anulável)
  • Quando os dependentes/filhos foram carregados e são rastreados pelo DbContext e quando eles existem apenas no banco de dados

Relação obrigatória com dependentes/filhos carregados

DeleteBehavior Ao excluir a entidade principal/pai Ao cortar a relação com a entidade principal/pai
Cascata Dependentes excluídos pelo EF Core Dependentes excluídos pelo EF Core
Restringir InvalidOperationException InvalidOperationException
NoAction InvalidOperationException InvalidOperationException
SetNull SqlException ao criar o banco de dados SqlException ao criar o banco de dados
ClientSetNull InvalidOperationException InvalidOperationException
ClientCascade Dependentes excluídos pelo EF Core Dependentes excluídos pelo EF Core
ClientNoAction DbUpdateException InvalidOperationException

Observações:

  • O padrão para relações obrigatórias como essa é Cascade.
  • O uso de qualquer opção que não seja a exclusão em cascata para as relações obrigatórias resultará em uma exceção quando SaveChanges for chamado.
    • Normalmente, essa é uma InvalidOperationException do EF Core, pois o estado inválido é detectado nos filhos/dependentes carregados.
    • ClientNoAction força o EF Core a não verificar a correção dos dependentes antes de enviá-los ao banco de dados. Portanto, nesse caso, o banco de dados gera uma exceção, que, em seguida, é encapsulada em uma DbUpdateException por SaveChanges.
    • SetNull é rejeitado ao criar o banco de dados, pois a coluna de chave estrangeira não é anulável.
  • Como os dependentes/filhos foram carregados, eles são sempre excluídos pelo EF Core e nunca permanecem para exclusão pelo banco de dados.

Relação obrigatória com dependentes/filhos não carregados

DeleteBehavior Ao excluir a entidade principal/pai Ao cortar a relação com a entidade principal/pai
Cascata Dependentes excluídos pelo banco de dados N/D
Restringir DbUpdateException N/D
NoAction DbUpdateException N/D
SetNull SqlException ao criar o banco de dados N/D
ClientSetNull DbUpdateException N/D
ClientCascade DbUpdateException N/D
ClientNoAction DbUpdateException N/D

Observações:

  • O corte de uma relação não é válido aqui, pois os dependentes/filhos não foram carregados.
  • O padrão para relações obrigatórias como essa é Cascade.
  • O uso de qualquer opção que não seja a exclusão em cascata para as relações obrigatórias resultará em uma exceção quando SaveChanges for chamado.
    • Normalmente, essa é uma DbUpdateException, porque os dependentes/filhos não foram carregados e, portanto, o estado inválido só pode ser detectado pelo banco de dados. Em seguida, SaveChanges encapsula a exceção de banco de dados em uma DbUpdateException.
    • SetNull é rejeitado ao criar o banco de dados, pois a coluna de chave estrangeira não é anulável.

Relação opcional com dependentes/filhos carregados

DeleteBehavior Ao excluir a entidade principal/pai Ao cortar a relação com a entidade principal/pai
Cascata Dependentes excluídos pelo EF Core Dependentes excluídos pelo EF Core
Restringir FKs dependentes definidas como nulas pelo EF Core FKs dependentes definidas como nulas pelo EF Core
NoAction FKs dependentes definidas como nulas pelo EF Core FKs dependentes definidas como nulas pelo EF Core
SetNull FKs dependentes definidas como nulas pelo EF Core FKs dependentes definidas como nulas pelo EF Core
ClientSetNull FKs dependentes definidas como nulas pelo EF Core FKs dependentes definidas como nulas pelo EF Core
ClientCascade Dependentes excluídos pelo EF Core Dependentes excluídos pelo EF Core
ClientNoAction DbUpdateException FKs dependentes definidas como nulas pelo EF Core

Observações:

  • O padrão para relações opcionais como essa é ClientSetNull.
  • Os dependentes/filhos nunca são excluídos, a menos que Cascade ou ClientCascade esteja configurado.
  • Todos os outros valores fazem com que as FKs dependentes sejam definidas como nulas pelo EF Core…
    • … com exceção de ClientNoAction, que instrui o EF Core a não tratar as chaves estrangeiras de dependentes/filhos quando a entidade principal/pai é excluída. O banco de dados, portanto, gera uma exceção, que é encapsulada como uma DbUpdateException por SaveChanges.

Relação opcional com dependentes/filhos não carregados

DeleteBehavior Ao excluir a entidade principal/pai Ao cortar a relação com a entidade principal/pai
Cascata Dependentes excluídos pelo banco de dados N/D
Restringir DbUpdateException N/D
NoAction DbUpdateException N/D
SetNull FKs dependentes definidas como nulas pelo banco de dados N/D
ClientSetNull DbUpdateException N/D
ClientCascade DbUpdateException N/D
ClientNoAction DbUpdateException N/D

Observações:

  • O corte de uma relação não é válido aqui, pois os dependentes/filhos não foram carregados.
  • O padrão para relações opcionais como essa é ClientSetNull.
  • Os dependentes/os filhos precisam ser carregados para evitar uma exceção de banco de dados, a menos que o banco de dados tenha sido configurado para fazer exclusões ou propagações de nulos em cascata.