Come posso gestire la concorrenza con persistenti In Calcolato proprietà in un aggregato Root tramite NHibernate?

StackOverflow https://stackoverflow.com/questions/3937389

Domanda

Ho la necessità di persistere una proprietà calcolata con una radice aggregato. Il calcolo si basa su entità figlio. Sto usando la radice per aggiungere / rimuovere i bambini tramite metodi di dominio, e questi metodi aggiornare la proprietà Calcola.

Un'entità bambino può essere aggiunto a una particolare radice da più utenti del sistema. Ad esempio, UtenteA può aggiungere un bambino di root123, e UtenteB può anche aggiungere un bambino di root123.

Come posso garantire che questa proprietà calcolato viene mantenuto con precisione quando più di un utente può essere l'aggiunta di entità figlio alla stessa radice in diverse transazioni? Nel mio caso particolare, la proprietà calcolata viene utilizzato per garantire che qualche limite non venga superato, come set per un'altra proprietà sulla radice.


Ecco un esempio più concreto del problema:

public class RequestForProposal : AggregateRoot {
    ...
    private ISet<Proposal> _proposals = new HashedSet<Proposal>();

    public virtual int ProposalLimit { get; set; }
    public virtual int ProposalCount { get; protected set; }

    public virtual IEnumerable<Proposal> Proposals {
        get { return _proposals; }
    }
    ...

    public virtual void AddProposal(User user, Content proposalContent) {
        if (ProposalCount >= ProposalLimit) {
            throw new ProposalLimitException("No more proposals are being accepted.");
        }

        var proposal = new Proposal(user, proposalContent);
        _proposals.Add(proposal);
        ProposalCount++;
    }

    public virtual void RemoveProposal(Proposal proposalToRemove) {
        _proposals.Remove(proposalToRemove);
        ProposalCount--;
    }
}

E se 2 utenti stanno presentazione delle proposte, più o meno nello stesso momento? L'interfaccia utente vede che il limite non è ancora stato raggiunto e mostra la pagina Web di presentare una proposta per gli utenti. Quando i primi sottomette utente, va tutto bene. Ora, il secondo utente sarà bene finché i primi sottomette utente prima il secondo, in modo che quando il secondo sottomette utente, i dati vengono recuperati dal DB e il limite sarà accurato.

E 'questo un punto controverso? Dovrei contare su vincoli nel DB (ProposalLimit> = ProposalCount) per quei rari casi in cui 2 utenti inviano quasi contemporaneamente?

È stato utile?

Soluzione

Se si dovesse mettere il Controllo regole di business (cioè controllo limite) all'interno di una transazione, sarà bene. Questo è il

  1. User pulsante Clic che gli incendi Add Proposta di comando
  2. Codice avvia una nuova transazione. Vedi qui per come vi suggerisco di utilizzare le transazioni
  3. caricare l'oggetto RequestForProposal dal db, o aggiornarla. Vi suggerisco di usare un blocco di aggiornamento.
  4. Aggiungi nuove proposte alla radice. Controllare il vincolo limite, un'eccezione non riesce.
  5. commit della transazione

Facendo in questo modo si utilizza il database controlli concorrenza . Io non credo che ci sia un altro modo di farlo.

Questo creerà qualche contesa, ma si può fare qualche passo per ridurre al minimo questo. Vale a dire fare in modo al punto 3 che la colonna db si seleziona da ha un indice su di esso. Ciò causerà un blocco di riga, invece di un blocco di pagina.

Se si utilizza un blocco di aggiornamento al punto 3, questo eviterà situazioni di stallo. Fondamentalmente, quando il secondo degli utenti presenta una proposta per la stessa Aggregate Root il db non ti consente di leggere fino a quando la prima transazione ha commesso.

Si dovrebbe anche prendere in considerazione l'aggiunta di un indice di db su Proposal.RequestForProposalId, aiuterà le prestazioni come quella è la colonna della proposta vengono caricati su. Io non sono al 100% se aiuta a minimizzare la portata di eventuali blocchi su quel tavolo, ma potrebbe ...

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