Domanda

Stiamo sviluppando un'applicazione .NET con la seguente architettura: livello di presentazione (utilizzando il modello MVC con ASP.NET MVC 2), livello di servizio, livello di accesso ai dati (utilizzando il modello di repository su Entity Framework).

Abbiamo deciso di mettere la gestione delle transazioni nel livello di servizio, ma non siamo sicuri di come implementarla. Vogliamo controllare interamente la transazione a livello di livello di servizio. Cioè, ogni volta che un controller chiama un metodo nel livello di servizio, deve essere un'operazione atomica per quanto riguarda gli aggiornamenti del database.

Se non esisteva alcuna relazione tra diversi servizi forniti nel livello di servizio, sarebbe semplice: ogni metodo dovrebbe commettere le modifiche alla fine della sua esecuzione (ovvero, chiamare il metodo di salvataggio sul contesto che utilizza). Ma a volte i servizi a livello di servizio lavorano insieme.

EG: Forniamo un servizio di spedizione che ha un metodo di conferma che riceve i seguenti parametri: l'ID di spedizione, un flag che indica se corrisponde a un nuovo cliente o uno esistente, l'ID cliente (nel caso in cui la conferma della spedizione sia per un esistente Cliente) e un nome del cliente (nel caso lo sia per un nuovo cliente). Se il flag è impostato su "nuovo cliente", il livello di servizio deve (a) creare il cliente e (b) confermare la spedizione. Per (a) il servizio di spedizione chiama il servizio clienti (che già implementa le convalide e la logica necessarie per creare un nuovo cliente e archiviarlo nel database).

Chi dovrebbe commettere i cambiamenti in questo scenario?

  • Il servizio clienti dovrebbe farlo? Non può commettere le modifiche dopo la creazione del nuovo cliente, perché qualcosa può andare storto più avanti nel metodo di conferma della spedizione, ma deve commettere le sue modifiche nel caso in cui è chiamata direttamente (in altri casi d'uso, fornito per creare un cliente).
  • Il controller che chiama il metodo di servizio dovrebbe farlo? Ma il controller non dovrebbe sapere nulla sulle transazioni, abbiamo deciso di mettere tutte le transazioni nel livello di servizio.
  • Un gestore delle transazioni nel livello dei servizi? Come progettarlo?, Chi lo chiama e quando?

Esiste un modello di design per questo che dovremmo seguire?

È stato utile?

Soluzione

Ho un commit () sul mio servizio, questo si impegna solo se l'UniTofwork viene creata dal servizio, se viene approvato nel costruttore che il commit non fa nulla.

Ho usato un secondo costruttore (interno) per il servizio:

public class MyService
{
private IUnitOfWork _uow;
private bool _uowInternal;

public MyService()
{
    _uow = new UnitOfWork();
    _uowInternal = false;
}

internal MyService(IUnitOfWork uow)
{
    _uow = uow;
    _uowInternal = true;
}
public MyServiceCall()
{
    // Create second service, passing in my UnitOfWork:
    var svc2 = new MySecondService(_uow);

    // Do your stuff with both services.
    ....
    // Commit my UnitOfWork, which will include all changes from svc2:
    Commit();
}

public void Commit()
{
    if(!_uowInternal)
        _uow.Commit();
}
}

Altri suggerimenti

In un'architettura simile con WCF e L2S anziché EF, abbiamo scelto di utilizzare le transazioni nella classe di implementazione dell'interfaccia di servizio principale. Abbiamo usato Transazione Per realizzare questo:

public void AServiceMethod() {
    using(TransactionScope ts = new TransactionScope()) {
         service1.DoSomething();
         service2.DoSomething();
         ts.Complete();
    }
}

Lo svantaggio principale è che la transazione potrebbe diventare grande. In tal caso, se ad esempio una delle chiamate di servizio nel blocco delle transazioni richiede solo l'accesso leadonly, lo avvolgiamo in un nidificato TransactionScope(TransactionScopeOption.Suppress) Blocca per evitare di bloccare ulteriormente le righe/tabelle nella durata della transazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top