2011-08-23 10 views
27

So che MongoDB non suppone supportare unità di lavoro, ecc. Ma penso che sarebbe bello implementare il repository che memorizzerebbe solo le intenzioni (simili ai criteri) e quindi eseguirà il commit loro al DB. Altrimenti in ogni metodo nel tuo repository devi creare una connessione a DB e quindi chiuderla. Se poniamo la connessione al DB in una classe BaseRepository, leghiamo il nostro repository al DB concreto ed è molto difficile testare gli archivi, per testare IoC che risolve i repository.Unità di lavoro in mongodb e C#

Creare una sessione in MongoDB è una cattiva idea? C'è un modo per separare la logica di connessione dal repository?

Ecco un codice di Rob Conery. È una buona idea connettersi sempre al tuo DB ad ogni richiesta? Qual è la migliore pratica?

C'è ancora una cosa. Immagina di voler fornire un indice per una collezione. In precedenza ho lavorato in un costruttore, ma con l'approccio di Rob non sembra logico farlo lì.

using Norm; 
    using Norm.Responses; 
    using Norm.Collections; 
    using Norm.Linq; 

    public class MongoSession { 

     private string _connectionString; 

     public MongoSession() { 
      //set this connection as you need. This is left here as an example, but you could, if you wanted, 
      _connectionString = "mongodb://127.0.0.1/MyDatabase?strict=false"; 
     } 

     public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class, new() { 
      //not efficient, NoRM should do this in a way that sends a single command to MongoDB. 
      var items = All<T>().Where(expression); 
      foreach (T item in items) { 
       Delete(item); 
      } 
     } 

     public void Delete<T>(T item) where T : class, new() { 
      using(var db = Mongo.Create(_connectionString)) 
      { 
       db.Database.GetCollection<T>().Delete(item); 
      } 
     } 

     public void DeleteAll<T>() where T : class, new() { 
      using(var db = Mongo.Create(_connectionString)) 
      { 
       db.Database.DropCollection(typeof(T).Name); 
      } 
     } 

     public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class, new() { 
      T retval = default(T); 
      using(var db = Mongo.Create(_connectionString)) 
      { 
       retval = db.GetCollection<T>().AsQueryable() 
         .Where(expression).SingleOrDefault(); 
      } 
      return retval; 
     } 

     public IQueryable<T> All<T>() where T : class, new() { 
      //don't keep this longer than you need it. 
      var db = Mongo.Create(_connectionString); 
      return db.GetCollection<T>().AsQueryable(); 
     } 

     public void Add<T>(T item) where T : class, new() { 
      using(var db = Mongo.Create(_connectionString)) 
      { 
       db.GetCollection<T>().Insert(item); 
      } 
     } 

     public void Add<T>(IEnumerable<T> items) where T : class, new() { 
      //this is WAY faster than doing single inserts. 
      using(var db = Mongo.Create(_connectionString)) 
      { 
       db.GetCollection<T>().Insert(items); 
      } 
     } 

     public void Update<T>(T item) where T : class, new() { 
      using(var db = Mongo.Create(_connectionString)) 
      { 
       db.GetCollection<T>().UpdateOne(item, item); 
      } 
     } 

     //this is just some sugar if you need it. 
     public T MapReduce<T>(string map, string reduce) { 
      T result = default(T); 
      using(var db = Mongo.Create(_connectionString)) 
      { 
      var mr = db.Database.CreateMapReduce(); 
      MapReduceResponse response = 
       mr.Execute(new MapReduceOptions(typeof(T).Name) { 
        Map = map, 
        Reduce = reduce 
       }); 
      MongoCollection<MapReduceResult<T>> coll = response.GetCollection<MapReduceResult<T>>(); 
      MapReduceResult<T> r = coll.Find().FirstOrDefault(); 
      result = r.Value; 
      } 
      return result; 
     } 

     public void Dispose() { 
      _server.Dispose(); 
     } 
    } 
+0

E riguardo l'iniezione di dipendenza tramite un framework (o auto-scritto)? – DrColossos

+0

@DrColossos, in realtà utilizzo un framework chiamato Castle.Windsor. Ho visto un codice di Rob Conery che simula le sessioni ma si connette a DB su ogni creazione/aggiornamento/cancellazione/ricerca e io no se è ottimale –

risposta

17

Non preoccuparti troppo di aprire e chiudere i collegamenti. Il driver MongoDB C# gestisce un pool di connessioni interne, pertanto non si verificheranno problemi di apertura e chiusura delle connessioni effettive ogni volta che si crea un nuovo oggetto MongoServer.

È possibile creare un'interfaccia repository che esponga la logica dei dati e creare un'implementazione MongoDB che viene iniettata dove è necessario. In questo modo, il codice di connessione specifico di MongoDB viene estratto dalla tua applicazione, che vede solo l'IRepository.

Fare attenzione nel tentativo di implementare un modello di tipo unità di lavoro con MongoDB. A differenza di SQL Server, non è possibile integrare più query in una transazione che è possibile eseguire il rollback in caso di errore.

Per un semplice esempio di un modello di repository con implementazioni MongoDB, SQL Server e JSON, consultare lo NBlog storage code. Utilizza Autofac IoC per iniettare repository concreti in un'app MV.NET di ASP.NET.

+0

Chris, grazie per la risposta. Ho esaminato il tuo codice per il repository. Nel costruttore si crea e si mantiene per tutta la durata degli oggetti un'istanza di MongoServer. Ad esempio, il codice di test dell'unità per IoC deve risolvere alcuni repository. Significa che il tuo build server potrebbe fallire perché non ci sono processi mongos in esso. E anche concettualmente non sembra OK –

+0

@Hohhi quelli sono test di integrazione piuttosto che unit test, si aspettano (e richiedono) un processo mongod in esecuzione localmente per passare. –

+0

Qual è il posto giusto per applicare l'indice, quindi? –

0

Se siete interessati ad un'implementazione simile a Rob Connery e di NBlog codice di stoccaggio, ma utilizzando il driver di MongoDB csharp 2.0 (cioè asincrona), si può guardare:

https://github.com/alexandre-spieser/mongodb-generic-repository

Si può quindi scrivere un repository personalizzato che eredita da BaseMongoRepository.

public interface ITestRepository : IBaseMongoRepository 
{ 
    void DropTestCollection<TDocument>(); 
    void DropTestCollection<TDocument>(string partitionKey); 
} 

public class TestRepository : BaseMongoRepository, ITestRepository 
{ 
    public TestRepository(string connectionString, string databaseName) : base(connectionString, databaseName) 
    { 
    } 

    public void DropTestCollection<TDocument>() 
    { 
     MongoDbContext.DropCollection<TDocument>(); 
    } 

    public void DropTestCollection<TDocument>(string partitionKey) 
    { 
     MongoDbContext.DropCollection<TDocument>(partitionKey); 
    } 
} 
Problemi correlati