Gestione delle transazioni nidificate .NET

4

Ho un progetto principale asp.net che è diviso nella seguente struttura

  • Regolatore
    • Conservare
      • Repository

Il controller riceve richieste e chiama gli archivi corretti responsabili delle azioni contro il database (Crea utenti, Aggiorna record, ecc.) Il modo in cui lo vedo il controller dovrebbe essere agnostico al database - non dovrebbe controllare le transazioni, o nemmeno essere consapevole della loro esistenza.

L'archivio crea una transazione e chiama i repository richiesti e i loro metodi CRUD richiesti.

Questo è abbastanza semplice. Tuttavia, spesso mi ritrovo a ripetere il codice, a causa della gestione delle transazioni.

A volte voglio aggiungere utenti e aggiungerli a un gruppo - Quindi se avessi un GroupsStore e un UsersStore - ora ho un GroupsUsersStore che fa esattamente lo stesso di quegli store, ma di mettendolo in una transazione.

Questo è ovviamente sbagliato, ma non riesco a pensare ad una soluzione migliore - dal momento che le transazioni non possono essere nidificate in SQL Server, e voglio che anche quei negozi funzionino in modo indipendente.

Come risolve questo problema?

    
posta gilmishal 01.12.2016 - 14:52
fonte

3 risposte

1

I tuoi negozi sembrano un livello aziendale, corretto? Suppongo che un determinato metodo nei negozi possa chiamare più repository per ottenere il suo lavoro, con tutto ciò che può essere ripristinato in caso di errore. In questo caso, il tuo negozio dovrebbe avviare la connessione e la transazione sql e consegnarli come dipendenze al repository.

All'interno di FooStore.cs:

public StoreResult<ResultThing> DoStuff(int stuff) 
{
     using (var connection = GetOpenConnection())
     using (var transaction = connection.BeginTransaction())
     {
          var fooRepo = new FooRepo(connection, transaction);
          fooRepo.DoThing(stuff); // calls connection.Execute(...)
          // add more repo calls here
          transaction.Commit();
          return new StoreResult<ResultThing>();
     }
}

Ora, StoreResult dovrà restituire alcuni tipi di dati di successo / fail / messaggistica per indicare al controller che lo ha chiamato quale tipo di risultato si è verificato.

    
risposta data 01.12.2016 - 17:01
fonte
1

Assegna alle classi "Store" un parametro booleano facoltativo del costruttore autocommit per controllare se devono gestire le transazioni da soli (ossia, commettere automaticamente dopo che il loro lavoro è stato eseguito), o se lasciano questo al chiamante. Il valore predefinito per questo parametro potrebbe essere true .

Quindi il tuo GroupsStore continuerà a commettere automaticamente per impostazione predefinita e anche il tuo UsersStore store, quando usato da solo.

Ora, per avere una transazione combinata "Gruppi e utenti", probabilmente creerai ancora una classe GroupsUsersStore separata, ma questa non deve più contenere alcun codice duplicato. Invece, può riutilizzare GroupsStore e UsersStore , chiamandoli entrambi con autocommit=false .

    
risposta data 01.12.2016 - 15:21
fonte
1

Sometimes I want to add users, and add them to a group - So If I had a GroupsStore, and a UsersStore - I now have a GroupsUsersStore that does exactly the same as those store, but by putting that in one transaction.

This is obviously wrong, but I can't think of a better solution - since transactions can't be nested in sql server, and I want those stores to work independently as well.

How do you solve such issue?

Penso che tu stia affrontando un problema dall'altra parte. Il controllo delle transazioni deve essere excersised solo su un livello applicativo. Quindi, se hai bisogno di controllare le transazioni a un livello più alto, di quanto fai ora, hai diverse scelte:

  • Negozi di refactoring (in realtà sono servizi sembra) in modo che ognuno possa eseguire tutte le operazioni senza uscire dai limiti. Si potrebbe voler unire negozi, per esempio. Ma fai attenzione all'obidience SRP .
  • Costruisci il livello di livello superiore della tua applicazione (livello di orchestrazione), che controllerà le transazioni e gli archivi delle chiamate quando necessario per eseguire un'operazione di bussiness.

So If I had a GroupsStore, and a UsersStore

Direi che hai bisogno di UserManager (o di qualsiasi altra cosa tu lo chiami), che può davvero gestire gli utenti come entità bussiness: assegnare utenti a gruppi ecc. Perché attualmente il tuo GroupsStore non è altro che un repository un po 'divino.

    
risposta data 20.12.2016 - 14:14
fonte

Leggi altre domande sui tag