Personalizando o comportamento da operação de excluir
A exclusão de um elemento geralmente provoca também a exclusão de seus elementos relacionados. Todas as relações conectadas a ele e quaisquer elementos filhos são excluídos. Esse comportamento é chamado de propagação de exclusão. Você pode personalizar a propagação da exclusão, por exemplo, para providenciar que os elementos adicionais relacionados sejam excluídos. Ao escrever o código do programa, você pode fazer com que a propagação de exclusão dependa do estado do modelo. Também é possível causar outras alterações em resposta a uma exclusão.
Este tópico inclui as seções a seguir:
Comportamento de exclusão padrão
Configurando a opção Propagar Exclusão de uma função
Substituindo o Fechamento da Exclusão – Use esta técnica em situações nas quais a exclusão possa levar à exclusão de elementos vizinhos.
Usando OnDeleting e OnDeleted – Use estes métodos em situações nas quais a resposta possa incluir outras ações, tais como atualização de um valor dentro ou fora do repositório.
Regras de exclusão – Use as regras para propagar atualizações de qualquer tipo no repositório para situações nas quais uma alteração possa levar a outras.
Eventos de exclusão – Use os eventos do repositório para propagar atualizações fora do repositório, por exemplo, para outros documentos do Visual Studio.
Desfazer Mesclagem – Use a operação Desfazer Mesclagem para desfazer a operação de mesclagem que anexa um elemento filho ao pai.
Comportamento de exclusão padrão
Por padrão, as seguintes regras regem a propagação da exclusão:
Se um elemento for excluído, todos os elementos incorporados também serão excluídos. Os elementos incorporados são os elementos de destino das relações de incorporação para os quais este elemento é a fonte. Por exemplo, se houver uma relação de incorporação de Álbum para Música, quando determinado Álbum for excluído, todas as suas músicas também serão excluídas.
Por outro lado, a exclusão de uma música não exclui o álbum.
Por padrão, a exclusão não se propaga ao longo das relações de referência. Se existir uma relação de referência ArtistPlaysOnAlbum de Álbum para Artista, a exclusão de um álbum não excluirá nenhum artista relacionado e a exclusão de um artista não excluirá nenhum álbum.
No entanto, a exclusão se propaga ao longo de algumas relações internas. Por exemplo, quando um elemento do modelo é excluído, sua forma no diagrama também é excluída. O elemento e a forma estão relacionados pela relação de referência PresentationViewsSubject.
Todo relacionamento conectado ao elemento, seja na origem ou no destino, é excluído. A propriedade de função do elemento na função oposta passa a não conter o elemento excluído.
Configurando a opção Propagar Exclusão de uma função
Você pode fazer com que a exclusão se propague ao longo da relação de referência ou de um filho incorporado ao seu pai.
Para configurar a propagação de exclusão
No diagrama de definição de DSL, selecione a função para a qual você deseja que a propagação seja excluída. A função é representada pela linha à esquerda ou à direita de uma caixa de relação de domínio.
Por exemplo, se você deseja especificar que sempre que um Álbum for excluído, os Artistas relacionados também sejam excluídos, selecione a função conectada ao Artista da classe de domínio.
Na janela Propriedades, defina a propriedade Propaga Exclusão.
Pressione F5 e verifique se:
Quando uma instância desse relacionamento é excluída, o elemento na função selecionada também é excluído.
Quando um elemento na função oposta é excluído, instâncias dessa relação são excluídas e os elementos relacionados a essa função são excluídos.
Você também pode ver a opção Propaga Exclusão na janela Detalhes de DSL. Selecione uma classe de domínio e, na janela Detalhes de DSL, abra a página Comportamento de Exclusão clicando no botão ao lado da janela. A opção Propagar é apresentada para a função oposta de cada relacionamento. A coluna Estilo da Exclusão indica se a opção Propagar está em sua configuração padrão, mas não tem nenhuma efeito separado.
Propagação de exclusão usando o código do programa
As opções no arquivo Definição de DSL só permitem que você escolha se a exclusão se propaga para um vizinho imediato ou não. Para implementar um esquema mais complexo de propagação de exclusão, você pode gravar o código do programa.
Dica
Para adicionar o código do programa à definição de DSL, crie um arquivo de código separado no projeto Dsl e grave as definições parciais para aumentar as classes na pasta Código Gerado.Para obter mais informações, consulte Escrevendo código para personalizar uma linguagem específica do domínio.
Definindo um fechamento de exclusão
A operação de exclusão usa a classe YourModelDeleteClosure para determinar quais os elementos excluir, de acordo com a uma seleção inicial. Ela chama ShouldVisitRelationship() e ShouldVisitRolePlayer() repetidamente, percorrendo o gráfico de relações. Você pode substituir esses métodos. ShouldVisitRolePlayer é fornecido com a identidade de um vínculo e o elemento de uma das funções do vínculo. Ele deve retornar um dos seguintes valores:
VisitorFilterResult.Yes– O elemento deve ser excluído e o caminhador deve prosseguir e tentar os vínculos de outros elementos.
VisitorFilterResult.DoNotCare – O elemento não deve ser excluído, a menos que outra consulta responda que deva ser excluído.
VisitorFilterResult.Never – O elemento não deve ser excluído, mesmo que outra consulta responda Yes, e o caminhador não deve tentar vínculos de outros elementos.
// When a musician is deleted, delete their albums with a low rating.
// Override methods in <YourDsl>DeleteClosure in DomainModel.cs
partial class MusicLibDeleteClosure
{
public override VisitorFilterResult ShouldVisitRolePlayer
(ElementWalker walker, ModelElement sourceElement, ElementLink elementLink,
DomainRoleInfo targetDomainRole, ModelElement targetRolePlayer)
{
ArtistAppearsInAlbum link = elementLink as ArtistAppearsInAlbum;
if (link != null
&& targetDomainRole.RolePlayer.Id == Album.DomainClassId)
{
// Count other unvisited links to the Album of this link.
if (ArtistAppearsInAlbum.GetLinksToArtists(link.Album)
.Where(linkAlbumArtist =>
linkAlbumArtist != link &&
!walker.Visited(linkAlbumArtist))
.Count() == 0)
{
// Should delete this role player:
return VisitorFilterResult.Yes;
}
else
// Don’t delete unless another relationship deletes it:
return VisitorFilterResult.DoNotCare;
}
else
{
// Test for and respond to other relationships and roles here.
// Not the relationship or role we’re interested in.
return base.ShouldVisitRolePlayer(walker, sourceElement,
elementLink, targetDomainRole, targetRolePlayer);
}
}
}
A técnica de fechamento garante que o conjunto de elementos e vínculos a serem excluídos seja determinado antes que a exclusão comece. O caminhador também combina os resultados de seu fechamento com os de outras partes do modelo.
No entanto, a técnica supõe que a exclusão afete apenas seus vizinhos no gráfico de relações: não é possível usar esse método para excluir um elemento em outra parte do modelo. Você não poderá usá-lo se quiser adicionar elementos ou fazer outras alterações em resposta a uma exclusão.
Usando OnDeleting e OnDeleted
Você pode substituir OnDeleting() ou OnDeleted() em uma classe de domínio ou em uma relação de domínio.
OnDeleting é chamado quando um elemento está prestes a ser excluído, mas antes que suas relações sejam desconectadas. Ele ainda é navegável de outros elementos e ainda está em store.ElementDirectory.
Se vários elementos forem excluído ao mesmo tempo, OnDeleting será chamado por todos eles antes de executar as exclusões.
IsDeleting é verdadeiro.
OnDeleted é chamado quando o elemento foi excluído. Ele permanece no heap do CLR para que um Desfazer possa ser realizado, se necessário, mas é desvinculado de outros elementos e removido de store.ElementDirectory. Para relações, a função ainda referencia usuários antigos.IsDeleted é verdadeiro.
OnDeleting e OnDeleted são chamados quando o usuário invoca Desfazer depois de criar um elemento e quando uma exclusão anterior é repetida em Refazer. Use this.Store.InUndoRedoOrRollback para evitar atualizar elementos de repositório nesses casos. Para obter mais informações, consulte Como usar transações para atualizar o modelo.
Por exemplo, o código a seguir exclui um Álbum quando sua última Música filha é excluída:
// Delete the parent Album when the last Song is deleted.
// Override methods in the embedding relationship between Album and Song:
partial class AlbumHasSongs
{
protected override void OnDeleted()
{
base.OnDeleted();
// Don't perform in-store actions in undo:
if (this.Store.InUndoRedoOrRollback) return;
// Relationship source and target still work:
// Don't bother if source is already on its way out:
if (!this.Album.IsDeleting && !this.Album.IsDeleted)
{
if (this.Album.Songs.Count == 0)
{
this.Album.Delete();
} } } }
Muitas vezes, é mais prático acionar a partir da exclusão da relação do que no elemento de função, pois isso funciona quando o elemento é excluído e quando a própria relação é excluída. No entanto, para uma relação de referência, propague a exclusão quando um elemento relacionado é excluído, mas não quando a própria relação for excluída. Este exemplo exclui um Álbum quando seu último Artista colaborador é excluído, mas não responde se as relações forem excluídas:
using System.Linq; ...
// Assumes a many-many reference relationship
// between Artist and Album.
partial class Artist
{
protected override void OnDeleting()
{
base.OnDeleting();
if (this.Store.InUndoRedoOrRollback) return;
List<Album> toDelete = new List<Album>();
foreach (Album album in this.Albums)
{
if (album.Artists.Where(artist => !artist.IsDeleting)
.Count() == 0)
{
toDelete.Add(album);
}
}
foreach (Album album in toDelete)
{
album.Delete();
} } }
Quando você executa Delete em um elemento, OnDeleting e OnDeleted são chamados. Esses métodos são realizados em linha, isto é, imediatamente antes e após a exclusão real. Se o seu código excluir dois ou mais elementos, OnDeleting e OnDeleted serão chamados em alternância em todos eles, um após o outro.
Regras e eventos de exclusão
Como uma alternativa aos manipuladores OnDelete, você pode definir regras e eventos de exclusão.
Regras Deleting e Delete são acionadas apenas em uma transação, e não em Desfazer ou Refazer. Você pode configurá-las para serem colocadas em fila para execução no final da transação em que a exclusão é realizada. As regras Deleting são sempre executadas antes de qualquer regra Deleted na fila.
Use regras para propagar alterações que afetam apenas os elementos no repositório, incluindo relações, elementos de diagrama e suas propriedades. Normalmente, uma regra Deleting é usada para propagar exclusão e uma regra Delete é usada para criar elementos e relações de reposição.
Para obter mais informações, consulte Regras propagam alterações dentro do modelo.
O evento de repositório Deleted é invocado no final de uma transação e é chamado após um desfazer ou refazer. Ele pode, portanto, ser usado para propagar exclusões a objetos fora do repositório, tais como arquivos, entradas de banco de dados ou outros objetos no Visual Studio.
Para obter mais informações, consulte Manipuladores de eventos propagam alterações fora do modelo.
Aviso
Quando um elemento é excluído, você pode acessar seus valores de propriedade de domínio, mas não é possível navegar nos vínculos de relação.No entanto, se você definir um evento excluído em um relacionamento, também poderá acessar os dois elementos que eram seus usuários.Assim, se você quiser responder à exclusão de um elemento de modelo, mas quiser acessar um elemento ao qual ele estava vinculado, defina um evento de exclusão no relacionamento em vez da classe de domínio do elemento modelo.
Exemplo de regras de exclusão
[RuleOn(typeof(Album), FireTime = TimeToFire.TopLevelCommit)]
internal class AlbumDeletingRule : DeletingRule
{
public override void ElementDeleting(ElementDeletingEventArgs e)
{
base.ElementDeleting(e);
// ...perform tasks to propagate imminent deletion
}
}
[RuleOn(typeof(Album), FireTime = TimeToFire.TopLevelCommit)]
internal class AlbumDeletedRule : DeleteRule
{
public override void ElementDeleted(ElementDeletedEventArgs e)
{
base.ElementDeleted(e);
// ...perform tasks such as creating new elements
}
}
// The rule must be registered:
public partial class MusicLibDomainModel
{
protected override Type[] GetCustomDomainModelTypes()
{
List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
types.Add(typeof(AlbumDeletingRule));
types.Add(typeof(AlbumDeletedRule));
// If you add more rules, list them here.
return types.ToArray();
}
}
Exemplo de evento Deleted
partial class NestedShapesSampleDocData
{
protected override void OnDocumentLoaded(EventArgs e)
{
base.OnDocumentLoaded(e);
DomainRelationshipInfo commentRelationship =
this.Store.DomainDataDirectory
.FindDomainRelationship(typeof(CommentsReferenceComponents));
this.Store.EventManagerDirectory.ElementDeleted.Add(commentRelationship,
new EventHandler<ElementDeletedEventArgs>(CommentLinkDeleted));
}
private void CommentLinkDeleted (object sender, ElementDeletedEventArgs e)
{
CommentsReferenceComponents link = e.ModelElement as CommentsReferenceComponents;
Comment comment = link.Comment;
Component component = link.Subject;
if (comment.IsDeleted)
{
// The link was deleted because the comment was deleted.
System.Windows.Forms.MessageBox.Show("Removed comment on " + component.Name);
}
else
{
// It was just the link that was deleted - the comment itself remains.
System.Windows.Forms.MessageBox.Show("Removed comment link to "
+ component.Name);
}
}
}
Desfazer Mesclagem
A operação que atribui um elemento filho ao pai é chamada de mesclagem. Ela ocorre quando um novo elemento ou grupo de elementos é criado a partir da caixa de ferramentas, ou transferida de outra parte do modelo, ou copiada da área de transferência. Além de criar uma relação de incorporação entre o pai e seu novo filho, a operação de mesclagem também pode definir relações adicionais, criar elementos auxiliares e definir valores de propriedades nos elementos. A operação de mesclagem é encapsulada em uma EMD (Diretiva de Mesclagem de Elementos).
Uma EMD também encapsula uma operação complementar desfazer mesclagem ou MergeDisconnect. Se você tiver um conjunto de elementos que foi construído usando uma mesclagem, é recomendável usar a operação desfazer mesclagem associada para remover um elemento dele se quiser deixar os elementos restantes em um estado consistente. A operação desfazer mesclagem normalmente usa as técnicas descritas nas seções anteriores.
Para obter mais informações, consulte Personalizando a criação e o movimento de elementos.
Consulte também
Conceitos
Personalizando o comportamento da operação de copiar
Personalizando a criação e o movimento de elementos
Outros recursos
Escrevendo código para personalizar uma linguagem específica do domínio