2011-08-23 15 views
27

Sé que se supone que MongoDB no es compatible con la unidad de trabajo, etc. Pero creo que sería bueno implementar el repositorio que almacenaría solo las intenciones (similar a los criterios) y luego ellos a la DB. De lo contrario, en cada método en su repositorio debe crear una conexión a DB y luego cerrarlo. Si colocamos la conexión a DB en alguna clase de BaseRepository, vinculamos nuestro repositorio a DB concreto y es realmente difícil probar repositorios, probar IoC que resuelven repositorios.Unidad de trabajo en mongodb y C#

¿Está creando una sesión en MongoDB una mala idea? ¿Hay alguna manera de separar la lógica de conexión del repositorio?

Aquí hay un código de Rob Conery. ¿Es una buena idea conectarse siempre a su base de datos en cada solicitud? cual es la mejor practica?

Hay una cosa más. Imagina que quiero proporcionar un índice para una colección. Anteriormente lo hice en un constructor pero con el enfoque de Rob esto parece fuera de lógica hacerlo allí.

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

¿Qué tal la inyección de dependencia a través de un marco (o auto-escrito)? – DrColossos

+0

@DrColossos, en realidad uso un framework llamado Castle.Windsor. He visto un código de Rob Conery simulando sesiones, pero se conecta a DB en cada creación/actualización/eliminación/búsqueda y no, si es óptimo –

Respuesta

17

No se preocupe demasiado por las conexiones de apertura y cierre. El controlador MongoDB C# mantiene un grupo de conexiones internas, por lo que no sufrirá gastos generales por la apertura y el cierre de las conexiones reales cada vez que cree un nuevo objeto MongoServer.

Puede crear una interfaz de repositorio que exponga su lógica de datos y crear una implementación de MongoDB que se inyecte donde sea necesario. De esta forma, el código de conexión específico de MongoDB se abstrae de su aplicación, que solo ve el IRepository.

Tenga cuidado al implementar un patrón de tipo de unidad de trabajo con MongoDB. A diferencia de SQL Server, no puede solicitar múltiples consultas en una transacción que se puede retrotraer si falla.

Para ver un ejemplo simple de un patrón de repositorio que tiene implementaciones MongoDB, SQL Server y JSON, consulte NBlog storage code. Utiliza Autofac IoC para inyectar repositorios concretos en una aplicación ASP.NET MVC.

+0

Chris, gracias por la respuesta. He investigado tu código para el repositorio. En el constructor, usted crea y mantiene durante toda la vida de los objetos una instancia de MongoServer. Por ejemplo, su código de prueba unitario para IoC tiene que resolver algún repositorio. Significa que su servidor de compilación puede fallar porque no hay un proceso de mongos en él. E incluso conceptualmente no parece estar bien –

+0

@Hohhi, esas son pruebas de integración en lugar de pruebas unitarias, esperan (y requieren) que se ejecute un proceso mongod que se ejecuta localmente. –

+0

¿Cuál es el lugar correcto para aplicar el índice? –

0

Si usted está interesado en una implementación similar a Rob Connery y NBlog código de almacenamiento, pero utilizando el controlador mongodb CSharp 2.0 (es asíncrona), se puede ver en:

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

entonces usted puede escribir un repositorio personalizado que hereda de 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); 
    } 
} 
Cuestiones relacionadas