I know that MongoDB is not supposed to support unit of work, etc. But I think it would be nice to implement the repository which would store only the intentions (similar to criteria) and then commit them to the DB. Otherwise in every method in your repository you have to create connection to DB and then close it. If we place the connection to DB in some BaseRepository class, then we tie our repository to concrete DB and it is really difficult to test repositories, to test IoC which resolve repositories.
Is creating a session in MongoDB a bad idea? Is there a way to separate the connection logic from repository?
Here is some code by Rob Conery. Is it a good idea to always connect to your DB on every request? What is the best practice?
There is one more thing. Imagine I want to provide an index for a collection. Previously I did in a constructor but with Rob's approach this seems out of logic to do it there.
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(); } }
Unit of Work is the concept related to the effective implementation of the repository pattern. non-generic repository pattern, generic repository pattern. Unit of Work is referred to as a single transaction that involves multiple operations of insert/update/delete and so on.
The unit of work class coordinates the work of multiple repositories by creating a single database context class shared by all of them.
The unit of work itself uses the interfaces defined in System. Data to be completely driver independent. That makes it quite easy to switch DB as long as you don't use anything but the SQL92 standard in your SQL statements. C# Shrink ▲ Copy Code.
No need for repositories and unit of work with Entity Framework Core.
Don't worry too much about opening and closing connections. The MongoDB C# driver maintains an internal connection pool, so you won't suffer overheads of opening and closing actual connections each time you create a new MongoServer
object.
You can create a repository interface that exposes your data logic, and build a MongoDB implementation that is injected where it's needed. That way, the MongoDB specific connection code is abstratced away from your application, which only sees the IRepository.
Be careful trying to implement a unit-of-work type pattern with MongoDB. Unlike SQL Server, you can't enlist multiple queries in a transaction that can be rolled back if one fails.
For a simple example of a repository pattern that has MongoDB, SQL Server and JSON implementations, check out the NBlog storage code. It uses Autofac IoC to inject concrete repositories into an ASP.NET MVC app.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With