2011-10-10 3 views
4

J'implémente RavenDB dans un projet et après quelques jours d'essai de la base de données je suis en train de structurer cette application mais j'ai une question. J'écris des couches de gestion pour chaque entité (presque) et j'ai une classe de référentiel unique qui gère les requêtes et le DocumentStore. Je suis confus sur la façon dont je devrais partager le DocumentStore le long des couches de services et gérer les transactions.Architecture d'application - Transactions avec RavenDB

Je montre un exemple où j'essaye de stocker et lire un document dans une transaction simple.

Un exemple du dépôt:

public class RavenRepository 
{ 
    private static DocumentStore _store; 
    private IDocumentSession _session; 

    public RavenRepository(DocumentStore store) 
    { 
     _store = (_store==null) ? new DocumentStore() { Url = "http://wsk-gcardoso:8081" } : store;   
    } 
    public T SingleOrDefault<T>(Func<T, bool> predicate) where T : BaseModel 
    { 
     using (var session = _store.OpenSession()) 
     { 
      return session.Query<T>().SingleOrDefault(predicate); 
     } 
    } 
    public T Add<T>(T item) where T : BaseModel 
    {    
     using (var session = _store.OpenSession()) 
     { 
      session.Advanced.AllowNonAuthoritiveInformation = this.AllowNonAuthoritiveInformation; 
      session.Store(item); 
      session.SaveChanges(); 
     } 
     return item; 
    } 
    public void Initialize() { 
     _store.Initialize(); 
    } 
    public void Dispose() { 
     _store.Dispose(); 
    } 
} 

Une couche d'affaires serait comme ceci:

public class NewsletterBusiness 
{ 
    private RavenRepository repository; 
    public NewsletterBusiness(RavenRepository ravenRepository) 
    {  
     repository = (ravenRepository == null) ? RavenRepository(null) : ravenRepository; 
    } 

    public Newsletter Add(Newsletter newsletter) 
    { 
     Newsletter news = repository.Add(newsletter); 
     return news; 
    } 
    public Newsletter GetById(long Id) 
    { 
     Newsletter news = repository.SingleOrDefault<Newsletter>(x => x.Id == Id); 
     return news; 
    } 
} 

Maintenant, je suis en train d'enregistrer et d'obtenir lire un objet (Bulletins d'information) dans le même transaction. De ce que j'ai lu, je dois définir le AllowNonAuthoritativeInformation du documentStore sur false pour attendre que la transaction soit terminée. Mais de la façon dont je traite les couches et le référentiel, est-ce que je stocke et interroge la base de données en une seule transaction?

Pour être honnête, je pense que je suis confus au sujet de la méthode OpenSession de magasin. Je pense que je confond la session avec la transaction.

Par exemple, ce code:

var repository = new RavenRepository(null); 
newsletterBusiness = new NewsletterBusiness(repository); 
repository.Initialize(); 
using (var tx = new TransactionScope()) 
{ 
    Newsletter new = newsletterBusiness.Add(new Newsletter { Title = "Created by Tests", Content = "Created By Tests" }); 

    Newsletter objectCreated = newsletterBusiness.GetById(new.Id); 
    repository.Dispose(); 
    tx.Complete(); 
} 

Si je crée une deuxième couche d'affaires (pour les images, par exemple) et je mis le picturesBusiness.repository = dépôt (le même « objet RavenRepository seted pour businessLayer) Je vais travailler dans la même session de la newsletterBusiness.repository?

picturesBusiness = new PicturesBusiness(repository); 
Picture pic = picturesBusiness.GetById(20); 

J'apprécierais vraiment aider à ce sujet, Salutations du Portugal!

Répondre

13

Vous n'utilisez pas RavenDB correctement, c'est pourquoi vous rencontrez ce problème. Vous pouvez considérer la session comme la connexion à la base de données. Dans votre modèle, vous créez une session distincte pour chaque type. Mais il n'y a vraiment aucune raison réelle pour laquelle vous voulez faire cela.

En fait, vous ne voulez pas voulez faire cela, car la session est parfaitement capable de gérer plusieurs types en même temps. En outre, ce que vous avez fait est en fait diminuer les chances de session pour optimiser des choses comme l'envoi de mises à jour dans un lot au serveur.

Si vous souhaitez avoir une écriture transactionnelle qui couvre les types, étant donné votre architecture, vous devez utiliser DTC, car chaque session différente est une connexion différente à la base de données. Si vous utilisiez le modèle Session par requête, vous n'auriez qu'une seule session et vous auriez une sémantique transactionnelle en appelant une seule fois SaveChanges().

+0

Merci pour votre réponse. –

2

Vous essayez d'abstrait la session de corbeau (qui est fondamentalement un UnitOfWork) par un modèle de référentiel.

Je vous suggérerais l'approche suivante: créer une abstraction UnitOfWork qui encapsulera la session ravenDB et en instanciera les dépôts. Voici quelques pseudo-codes:

public class RavenUnitOfWork { 
    private IDocumentSession m_session; 

    public UnitOfWork() { 
     // initialize m_session here 
    } 

    public Repository<T> GetRepository() { 
     return new Repository<T>(m_session); 
    } 

    public void Commit() { 
     m_session.SaveChanges(); 
    } 
} 

public class RavenRepository<T> { 
    public Repository(IDocumentSession session) { 
     // Store the session 
    } 
    public T Load(string id) {...} 
    public void Store(T entity) {...} 
    public void Delete(T entity) {...} 
    public IQueryable<T> Query() {...} 
} 

Ici vous implémentez explicitement ces modèles.

P.S .: Bien sûr, vous pouvez déclarer IUnitOfWork et IRepository à votre goût ...