.NET MongoDB数据仓储和工作单元模式封装



一、引言

在.NET开发中,MongoDB作为一种高性能、灵活的NoSQL数据库,常用于存储和管理大量数据。为了更好地组织代码结构,提高开发效率和代码可维护性,可以将数据访问层与业务逻辑层解耦,使用数据仓储(Repository)模式和工作单元(UnitOfWork)模式来封装MongoDB数据库操作。数据仓储模式通过抽象出通用的CRUD方法,使业务逻辑层无需关心数据的存储细节;工作单元模式则负责协调多个仓储操作,统一管理事务,确保数据的一致性。

二、安装MongoDB.Driver

首先,需要安装MongoDB的官方.NET驱动程序MongoDB.Driver。可以通过NuGet包管理器进行安装:

dotnet add package MongoDB.Driver

或者使用Package Manager:

Install-Package MongoDB.Driver

三、定义MongoDB上下文

创建一个MongoDB上下文类,用于封装数据库连接和集合的获取。例如:

public class MongoContext : IDisposable
{
    private readonly IMongoDatabase _database;
    private readonly MongoClient _client;

    public MongoContext(string connectionString, string databaseName)
    {
        _client = new MongoClient(connectionString);
        _database = _client.GetDatabase(databaseName);
    }

    public IMongoCollection GetCollection(string collectionName)
    {
        return _database.GetCollection(collectionName);
    }

    public void Dispose()
    {
        _client.Dispose();
    }
}

这里使用IMongoDatabase接口来获取MongoDB数据库实例,并提供了GetCollection方法来获取指定集合。

四、定义数据仓储接口和实现

数据仓储接口定义了通用的CRUD操作方法,例如:

public interface IRepository<Twhere T : class
{
    Task AddAsync(T entity);
    Task> GetAllAsync();
    Task GetByIdAsync(string id);
    Task UpdateAsync(T entity);
    Task DeleteAsync(string id);
}

然后实现该接口,创建一个具体的仓储类:

public class Repository<T> : IRepository<Twhere T : class
{
    private readonly IMongoCollection _collection;

    public Repository(IMongoCollection collection)
    {
        _collection = collection;
    }

    public async Task AddAsync(T entity)
    {
        await _collection.InsertOneAsync(entity);
    }

    public async Task> GetAllAsync()
    {
        return await _collection.Find(Builders.Filter.Empty).ToListAsync();
    }

    public async Task GetByIdAsync(string id)
    {
        var filter = Builders.Filter.Eq("_id", id);
        return await _collection.Find(filter).FirstOrDefaultAsync();
    }

    public async Task UpdateAsync(T entity)
    {
        var filter = Builders.Filter.Eq("_id", entity.GetType().GetProperty("_id").GetValue(entity));
        await _collection.ReplaceOneAsync(filter, entity);
    }

    public async Task DeleteAsync(string id)
    {
        var filter = Builders.Filter.Eq("_id", id);
        await _collection.DeleteOneAsync(filter);
    }
}

这里使用了MongoDB.Driver提供的API来实现具体的CRUD操作。

五、实现工作单元模式

工作单元模式负责协调多个仓储操作,并统一管理事务。定义一个工作单元接口:

public interface IUnitOfWork : IDisposable
{
    Task<intCommitAsync();
    void RegisterNew(T entity) where T : class;
    void RegisterModified(T entity) where T : class;
    void RegisterDeleted(T entity) where T : class;
}

然后实现该接口,创建一个工作单元类:

public class UnitOfWork : IUnitOfWork
{
    private readonly MongoContext _context;
    private readonly List> _commands = new List>();

    public UnitOfWork(MongoContext context)
    {
        _context = context;
    }

    public async Task<intCommitAsync()
    {
        using (var session = await _context.Client.StartSessionAsync())
        {
            session.StartTransaction();
            try
            {
                foreach (var command in _commands)
                {
                    await command();
                }
                await session.CommitTransactionAsync();
                return _commands.Count;
            }
            catch (Exception)
            {
                await session.AbortTransactionAsync();
                return 0;
            }
            finally
            {
                _commands.Clear();
            }
        }
    }

    public void RegisterNew(T entity) where T : class
    {
        _commands.Add(async () => await _context.GetCollection(typeof(T).Name).InsertOneAsync(entity));
    }

    public void RegisterModified(T entity) where T : class
    {
        var filter = Builders.Filter.Eq("_id", entity.GetType().GetProperty("_id").GetValue(entity));
        _commands.Add(async () => await _context.GetCollection(typeof(T).Name).ReplaceOneAsync(filter, entity));
    }

    public void RegisterDeleted(T entity) where T : class
    {
        var filter = Builders.Filter.Eq("_id", entity.GetType().GetProperty("_id").GetValue(entity));
        _commands.Add(async () => await _context.GetCollection(typeof(T).Name).DeleteOneAsync(filter));
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

这里使用了MongoDB的事务功能来确保多个操作的原子性。

六、使用示例

以下是如何使用封装好的数据仓储和工作单元模式进行数据库操作的示例:

// 创建MongoDB上下文
var context = new MongoContext("mongodb://localhost:27017""YourDatabaseName");

// 创建工作单元实例
var unitOfWork = new UnitOfWork(context);

// 创建仓储实例
var userRepository = new Repository(context.GetCollection("Users"));

// 添加用户
var newUser = new User { Name = "张三", Email = "zhangsan@example.com" };
unitOfWork.RegisterNew(newUser);

// 更新用户
var userToUpdate = await userRepository.GetByIdAsync("existingUserId");
userToUpdate.Email = "updated@example.com";
unitOfWork.RegisterModified(userToUpdate);

// 删除用户
unitOfWork.RegisterDeleted(new User { Id = "userIdToDelete" });

// 提交事务
await unitOfWork.CommitAsync();

通过这种方式,可以方便地进行数据库的CRUD操作,并且确保了数据的一致性。

七、总结

通过封装.NET MongoDB的数据仓储和工作单元模式,可以有效地解耦业务逻辑层与数据访问层,提高代码的可维护性和可重用性。同时,工作单元模式的引入,使得在处理复杂的业务场景时,能够更好地管理事务,确保数据的一致性和完整性。在实际开发中,可以根据具体需求对这些封装进行扩展和优化,以满足不同的业务需求。


请使用浏览器的分享功能分享到微信等