Usar transações para atualizar o modelo

As transações garantem que as alterações feitas no repositório sejam tratadas como um grupo. As alterações agrupadas podem ser confirmadas ou revertidas como uma única unidade.

Sempre que o código do programa modifica, adiciona ou exclui qualquer elemento no Repositório do SDK de Visualização e Modelagem do Visual Studio, ele deve fazer isso dentro de uma transação. Deve haver uma instância ativa de Transaction associada ao Repositório quando a alteração ocorrer. Isso se aplica a todos os elementos de modelo, relações, formas, diagramas e suas propriedades.

O mecanismo de transação ajuda você a evitar estados inconsistentes. Se ocorrer um erro durante uma transação, todas as alterações serão revertidas. Se o usuário executar um comando Desfazer, cada transação recente será tratada como uma única etapa. O usuário não pode desfazer partes de uma alteração recente, a menos que você as coloque explicitamente em transações separadas.

Abrindo uma transação

O método mais conveniente de gerenciar uma transação é com uma instrução using embutida em uma instrução try...catch:

Store store; ...
try
{
  using (Transaction transaction =
    store.TransactionManager.BeginTransaction("update model"))
    // Outermost transaction must always have a name.
  {
    // Make several changes in Store:
    Person p = new Person(store);
    p.FamilyTreeModel = familyTree;
    p.Name = "Edward VI";
    // end of changes to Store

    transaction.Commit(); // Don't forget this!
  } // transaction disposed here
}
catch (Exception ex)
{
  // If an exception occurs, the Store will be
  // rolled back to its previous state.
}

Se ocorrer uma exceção que impeça a final Commit() durante as alterações, a Store será redefinida para seu estado anterior. Isso ajuda você a garantir que os erros não deixem o modelo em um estado inconsistente.

Você pode fazer qualquer número de alterações dentro de uma transação. Você pode abrir novas transações dentro de uma transação ativa. As transações aninhadas devem ser confirmadas ou revertidas antes que a transação as que contém seja encerrada. Para obter mais informações, confira o exemplo para a propriedade TransactionDepth.

Para tornar as alterações permanentes, você deve Commit a transação antes que ela seja descartada. Se ocorrer uma exceção que não seja capturada dentro da transação, a Store será redefinida para seu estado anterior às alterações.

Revertendo uma transação

Para garantir que a Store permaneça em seu estado ou reverta para ele antes da transação, você pode usar qualquer uma dessas táticas:

  1. Gere uma exceção que não é capturada dentro do escopo da transação.

  2. Reverta explicitamente a transação:

    this.Store.TransactionManager.CurrentTransaction.Rollback();
    

As transações não afetam objetos que não pertencem à Store

As transações regem apenas o estado da Store. Elas não podem desfazer alterações parciais feitas em itens externos, como arquivos, bancos de dados ou objetos declarados com tipos comuns fora da definição de DSL.

Se uma exceção puder deixar essa alteração inconsistente com a Store, você deverá lidar com essa possibilidade no manipulador de exceção. Uma maneira de garantir que os recursos externos permaneçam sincronizados com os objetos da Store é associar cada objeto externo a um elemento na loja usando manipuladores de eventos. Para obter mais informações, confira Manipuladores de eventos propagam alterações fora do modelo.

Regras disparam no final de uma transação

No final de uma transação, antes que a transação seja descartada, as regras anexadas aos elementos no repositório são acionadas. Cada regra é um método que é aplicado a um elemento de modelo que foi alterado. Por exemplo, há regras de "correção" que atualizam o estado de uma Forma quando seu elemento de modelo é alterado e que criam uma Forma quando um elemento de modelo é criado. Não há nenhuma ordem de disparo especificada. Uma alteração feita por uma regra pode disparar outra regra.

Você pode definir suas próprias regras. Para obter mais informações sobre as regras, confira Responder a alterações e propagá-las.

As regras não são disparadas após um desfazer, um refazer ou um comando de reversão.

Contexto de transação

Cada transação tem um dicionário no qual você pode armazenar as informações desejadas:

store.TransactionManager

.CurrentTransaction.TopLevelTransaction

.Context.Add(aKey, aValue);

Isso é especialmente útil para transferir informações entre as regras.

Estado da transação

Em alguns casos, você precisa evitar propagar uma alteração se a alteração for causada por desfazer ou refazer uma transação. Isso pode acontecer, por exemplo, se você escrever um manipulador de valor de propriedade que possa atualizar outro valor na Store. Como a operação de desfazer redefine todos os valores na Store para seus estados anteriores, não é necessário calcular os valores atualizados. Use este código:

if (!this.Store.InUndoRedoOrRollback) {...}

As regras podem ser acionadas quando a store está sendo carregada inicialmente a partir de um arquivo. Para evitar responder a essas alterações, use:

if (!this.Store.InSerializationTransaction) {...}