IT

mongodb 및 C# 단위 작업

itgroup 2023. 6. 27. 22:06
반응형

mongodb 및 C# 단위 작업

MongoDB는 작업 단위 등을 지원하지 않는 것으로 알고 있습니다.하지만 (기준과 유사하게) 의도만 저장하고 DB에 커밋하는 저장소를 구현하는 것이 좋을 것 같습니다.그렇지 않으면 리포지토리의 모든 방법에서 DB에 대한 연결을 만든 다음 닫아야 합니다.일부 BaseRepository 클래스에 DB에 대한 연결을 설정하면 저장소를 구체적인 DB에 연결합니다. 그러면 저장소를 테스트하고 저장소를 해결하는 IoC를 테스트하는 것이 매우 어렵습니다.

MongoDB에서 세션을 만드는 것이 나쁜 생각입니까?연결 로직을 저장소에서 분리할 수 있는 방법이 있습니까?

여기 롭 코너리의 코드가 있습니다.요청할 때마다 항상 DB에 연결하는 것이 좋은 생각입니까?가장 좋은 방법은 무엇입니까?

한가지가 더 있습니다.컬렉션에 대한 인덱스를 제공하려고 합니다.이전에 저는 건설업자였지만 Rob의 접근 방식으로 인해 논리적으로 맞지 않는 것처럼 보입니다.

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

연결을 열고 닫는 것에 대해 너무 걱정하지 마십시오.MongoDBC# 드라이버는 내부 연결 풀을 관리하므로 새 연결을 만들 때마다 실제 연결을 열고 닫는 오버헤드가 발생하지 않습니다.MongoServer물건.

데이터 로직을 노출하는 저장소 인터페이스를 만들고 필요한 곳에 주입되는 MongoDB 구현을 구축할 수 있습니다.이렇게 하면, MongoDB 특정 연결 코드가 IR 저장소만 보는 응용 프로그램에서 추상화됩니다.

MongoDB로 작업 단위 유형 패턴을 구현할 때 주의해야 합니다.SQL Server와 달리 트랜잭션에 여러 개의 쿼리를 등록할 수 없습니다. 이 트랜잭션은 실패할 경우 롤백할 수 있습니다.

MongoDB, SQL Server 및 JSON 구현이 있는 저장소 패턴의 간단한 예를 보려면 NBlog 스토리지 코드를 확인하십시오.Autofac IoC를 사용하여 ASP.NET MVC 앱에 구체적인 리포지토리를 주입합니다.

디자인 패턴을 조사하면서 에 대한 기본 저장소 패턴을 만들었습니다.NetCore 및 MongoDB.MongoDB 문서를 읽다가 MongoDB의 트랜잭션에 대한 기사를 발견했습니다.기사에서 다음과 같이 명시했습니다.

버전 4.0부터 MongoDB는 복제본 세트에 대해 다중 문서 트랜잭션을 수행할 수 있는 기능을 제공합니다.

인터튜브들을 둘러보면서 저는 MongoDB를 위한 Unit of Work 패턴을 정말 잘 구현하는 라이브러리를 발견했습니다.

Rob Connery 및 NBlog 스토리지 코드와 유사하지만 mongodbcsharp 드라이버 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);
    }
}

간단히

이 너겟 패키지 UnitOf Work를 사용할 수 있습니다.MongoDb.이것은 포장지입니다.MongoDb.Driver몇 가지 유용한 기능과 기능이 있습니다.또한 샘플 코드와 비디오(ru)도 찾을 수 있습니다.

연결 설정 읽기

// read MongoDb settings from appSettings.json
services.AddUnitOfWork(configuration.GetSection(nameof(DatabaseSettings)));

// --- OR ----

// use hardcoded
services.AddUnitOfWork(config =>
{
    config.Credential = new CredentialSettings { Login = "sa", Password = "password" };
    config.DatabaseName = "MyDatabase";
    config.Hosts = new[] { "Localhost" };
    config.MongoDbPort = 27017;
    config.VerboseLogging = false;
});

주사제

namespace WebApplicationWithMongo.Pages
{
    public class IndexModel : PageModel
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly ILogger<IndexModel> _logger;

        public IndexModel(IUnitOfWork unitOfWork, ILogger<IndexModel> logger)
        {
            _unitOfWork = unitOfWork;
            _logger = logger;
        }

        public IPagedList<Order>? Data { get; set; }
    }
}

주입 후 저장소를 얻을 수 있습니다.

리포지토리 가져오기

public async Task<IActionResult> OnGetAsync(int pageIndex = 0, int pageSize = 10)
{
    var repository = _unitOfWork.GetRepository<Order, int>();
    Data = await repository.GetPagedAsync(pageIndex, pageSize, FilterDefinition<Order>.Empty, HttpContext.RequestAborted);
    return Page();
}

GetPagedAsync 유용한 구현 중 입니다.

트랜잭션

ACID 작업(거래)이 필요한 경우 사용할 수 있습니다.IUnitOfWork(복제 세트를 올바르게 설정해야 합니다.)예:


await unitOfWork.UseTransactionAsync<OrderBase, int>(ProcessDataInTransactionAsync1, HttpContext.RequestAborted, session);

ProcessDataInTransactionAsync1다음과 같이 보일 수 있습니다.

async Task ProcessDataInTransactionAsync1(IRepository<OrderBase, int> repositoryInTransaction, IClientSessionHandle session, CancellationToken cancellationToken)
{
    await repository.Collection.DeleteManyAsync(session, FilterDefinition<OrderBase>.Empty, null, cancellationToken);

    var internalOrder1 = DocumentHelper.GetInternal(99);
    await repositoryInTransaction.Collection.InsertOneAsync(session, internalOrder1, null, cancellationToken);
    logger!.LogInformation("InsertOne: {item1}", internalOrder1);

    var internalOrder2 = DocumentHelper.GetInternal(100);
    await repositoryInTransaction.Collection.InsertOneAsync(session, internalOrder2, null, cancellationToken);
    logger!.LogInformation("InsertOne: {item2}", internalOrder2);

    var filter = Builders<OrderBase>.Filter.Eq(x => x.Id, 99);
    var updateDefinition = Builders<OrderBase>.Update.Set(x => x.Description, "Updated description");
    var result = await repositoryInTransaction.Collection
        .UpdateOneAsync(session, filter, updateDefinition, new UpdateOptions { IsUpsert = false }, cancellationToken);

    if (result.IsModifiedCountAvailable)
    {
        logger!.LogInformation("Update {}", result.ModifiedCount);
    }

    throw new ApplicationException("EXCEPTION! BANG!");
}

이 너겟은 오픈소스 칼라봉가입니다.작업 단위.몽고DB

언급URL : https://stackoverflow.com/questions/7160021/unit-of-work-in-mongodb-and-c-sharp

반응형