Pergunta

Eu tenho o seguinte código que está em uma transação. Não tenho certeza de onde/quando deveria estar cometendo minha unidade de trabalho.

De propósito, não mencionei que tipo de resposta estou usando - por exemplo. Linq-to-SQL, Entity Framework 4, Nibernate, etc.

Se alguém sabe onde, eles podem explicar por que disseram, onde? (Estou tentando entender o padrão através do (s) exemplo (s), em vez de apenas fazer com que meu código funcione).

Aqui está o que eu tenho:-

using
(
    TransactionScope transactionScope =
        new TransactionScope
        (
            TransactionScopeOption.RequiresNew,
            new TransactionOptions
                { IsolationLevel = IsolationLevel.ReadUncommitted }
        )
)
{
    _logEntryRepository.InsertOrUpdate(logEntry);
    //_unitOfWork.Commit();  // Here, commit #1 ?

    // Now, if this log entry was a NewConnection or an LostConnection,
    // then we need to make sure we update the ConnectedClients.
    if (logEntry.EventType == EventType.NewConnection)
    {
        _connectedClientRepository.Insert(
            new ConnectedClient { LogEntryId = logEntry.LogEntryId });
        //_unitOfWork.Commit(); // Here, commit #2 ?
    }

    // A (PB) BanKick does _NOT_ register a lost connection,
    // so we need to make sure we handle those scenario's as a LostConnection.
    if (logEntry.EventType == EventType.LostConnection ||
        logEntry.EventType == EventType.BanKick)
    {
        _connectedClientRepository.Delete(
            logEntry.ClientName, logEntry.ClientIpAndPort);
        //_unitOfWork.Commit(); // Here, commit #3 ?
    }

    _unitOfWork.Commit(); // Here, commit #4 ?
    transactionScope.Complete();
}
Foi útil?

Solução

Comprometa -se em #4 Depois de todas as operações com todos os repositórios. Se você se comprometer com antecedência, as alterações feitas após essa chamada não serão comprometidas.

Outras dicas

Um bom ponto de partida para responder a essa pergunta é a definição de unidade de trabalho a partir de padrões de arquitetura corporativa (http://martinfowler.com/eaacatalog/unitofwork.html ):

Mantém uma lista de objetos afetados por uma transação comercial e coordena a redação das mudanças e a resolução de problemas de simultaneidade.

Os limites da sua unidade de trabalho são definidos pelos limites da sua transação comercial - nesse caso, sinônimos dos limites da transação do banco de dados (mas no caso de uma transação comercial longa que abrange várias solicitações que podem não ser o caso ).

Trabalhando para trás da definição acima e com base na minha compreensão do código mostrado, você deve comprometer a unidade de trabalho no final da transação comercial (#4).

Como um aparte, seus escopos de transação de banco de dados devem sempre ser menores do que o escopo do seu Uow (ou seja, o escopo do TX reside entre a chamada para uow.Begin () e uow.commit ()). Se o seu Uow abranger várias transações de banco de dados, você usaria uma transação de compensação para "reequilibrar" o Uow se uma das transações internas falhasse. Nesse caso, e especialmente se o seu Uow estiver criando seus próprios limites de transação de banco de dados em uow.begin () e uow.commit () eu removeria o escopo da transação, pois isso está simplesmente adicionando ruído desnecessário ao código.

Supondo que o seu armazenamento de dados esteja atribuindo IDs, você deve comprometer o número 1 (com o Nibernate que você deve descartar) e depois no final 4.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top