Единица работы в mongodb и C # - PullRequest
28 голосов
/ 23 августа 2011

Я знаю, что MongoDB не должен поддерживать единицу работы и т. Д. Но я думаю, что было бы неплохо реализовать репозиторий, в котором будут храниться только намерения (аналогичные критериям), а затем зафиксировать их в БД. В противном случае в каждом методе вашего репозитория вы должны создать соединение с БД, а затем закрыть его. Если мы помещаем соединение с БД в некоторый класс BaseRepository, то мы привязываем наш репозиторий к конкретной БД, и действительно трудно тестировать репозитории, тестировать IoC, который разрешает репозитории.

Является ли создание сессии в MongoDB плохой идеей? Есть ли способ отделить логику подключения от репозитория?

Вот код Роба Конери. Это хорошая идея, чтобы всегда подключаться к вашей БД при каждом запросе? Какова лучшая практика?

Есть еще одна вещь. Представьте, что я хочу предоставить индекс для коллекции. Раньше я делал это в конструкторе, но с подходом Роба это кажется логичным, чтобы делать это там.

 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();
        }
    }

Ответы [ 3 ]

18 голосов
/ 24 августа 2011

Не беспокойтесь об открытии и закрытии соединений.Драйвер MongoDB C # поддерживает внутренний пул соединений, поэтому вы не будете страдать от затрат на открытие и закрытие реальных соединений каждый раз, когда создаете новый MongoServer объект.

Вы можете создать интерфейс репозитория, который предоставляет ваши данныелогики, и построить реализацию MongoDB, которая будет внедрена, где это необходимо.Таким образом, специальный код подключения MongoDB удаляется от вашего приложения, которое видит только IRepository.

Будьте осторожны, пытаясь реализовать шаблон типа единицы работы с MongoDB.В отличие от SQL Server, в транзакцию нельзя включить несколько запросов, которые можно откатить в случае сбоя.

Для простого примера шаблона репозитория, в котором есть реализации MongoDB, SQL Server и JSON, ознакомьтесь с Код хранилища NBlog .Он использует Autofac IoC для внедрения конкретных хранилищ в приложение ASP.NET MVC.

0 голосов
/ 13 мая 2019

При исследовании шаблонов проектирования я создавал базовый шаблон репозитория для .Net Core и MongoDB.Читая документацию MongoDB, я наткнулся на статью о транзакциях в MongoDB .В статье было указано, что:

Начиная с версии 4.0, MongoDB предоставляет возможность выполнять многодокументные транзакции с наборами реплик.через библиотеку , которая действительно хорошо справляется с реализацией шаблона Unit of Work для MongoDB.

0 голосов
/ 27 февраля 2016

Если вас интересует реализация, аналогичная коду хранения Роба Коннери и NBlog, но использующая драйвер mongodb csharp 2.0 (то есть асинхронный), вы можете посмотреть:

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

Затем вы можете написать собственный репозиторий, унаследованный от 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);
    }
}
...