C# Mongodb 驱动程序 : Translate Action into an UpdateDefinition

标签 c# mongodb mongodb-.net-driver

我正在尝试将更新推广到我的 mongodb,这样我就可以更新我的数据 - 存储不可知。使用 EntityFramework,这非常容易,因为它具有更改跟踪功能,因此我可以将业务逻辑和特定于数据库的操作分开。至于 MongoDb,就没那么容易了,因为我必须创建这些 UpdateDefinitions,才能对文档进行更新。

模仿此操作的一种简单方法是使用 ReplaceOneAsync,但这不是一种选择,因为不止一方可能同时写入我的集合。例如,我在我的应用程序中将它用于聊天系统。

我想做这样的事情:

public class MongoActionWrapper<TCollection>
{
    public MongoActionWrapper(Action<TCollection> updateAction)
    {
        UpdateAction = updateAction;
    }

    public Action<TCollection> UpdateAction { get; }
}

然后我有我的 MongoRepository:

public abstract class BaseMongoRepository<TAggregate, TCollection> : IRepository<TAggregate> where TAggregate : BaseAggregateRoot, IMongoAggregate<TCollection>
{
    private readonly IMongoCollection<TCollection> _mongoCollection;

    protected BaseMongoRepository(IMongoCollection<TCollection> mongoCollection)
    {
        _mongoCollection = mongoCollection;
    }

    public async void SaveAsync(TAggregate aggregate)
    {
        var state = aggregate.GetState();
        foreach (var action in state.ActionsToExecuteOnCollection)
        {
            await _mongoCollection.UpdateOneAsync<TCollection>(aggregate.GetSelector(), action.UpdateAction);
        }
    }
}

我想在集合而不是 UpdateDefinition 上执行操作的位置。或者以某种方式将我的 Action 转换为 UpdateDefinition。

这将使我能够在列表(或我想存储数据的任何其他集合)上应用相同的更新,这样我就不会被迫留在 mongodb 上。

到目前为止,我唯一的解决方案是让我的 UpdateAction 更像一个描述更新的对象,然后在我想将其保存在 mongodb 中时转换这些对象。这样我就可以将它们转换为 Actions 并将它们应用到我的收藏或我选择的任何其他数据库。

我希望有人有想法,因为我在这里没有其他选择。

最佳答案

我不确定你是如何使用 Action delegate 来做到这一点的,但是如果你想在单个 AggregateRoot 上重现 EntityFramework,比如 Read-Through、Write-Through 缓存和多个并发写入,你可以尝试这样的事情:

public abstract class AggregateRoot<T> where T : AggregateRoot<T>
{
    internal UpdateDefinition<T> UpdateDefinition { get; internal set; }
    internal void Aggregate(UpdateDefinition<T> component)
    {
        if (component == null)
        {
            throw new ArgumentNullException("component");
        }

        if (this.UpdateDefinition == null)
        {
            this.UpdateDefinition = component;
        }
        else
        {
            this.UpdateDefinition = Builders<T>.Update.Combine
                (this.UpdateDefinition, component);
        }
    }
}

并且比存储库基类中的:

public class Repository<T> where T : AggregateRoot<T>
{
    private ConcurrentDictionary<ObjectId, T> cache 
        = new ConcurrentDictionary<ObjectId, T>();

    private IMongoCollection<T> collection;

    public Repository(string connectionString, string databaseName, string collectionName)
    {
        collection = new MongoClient(connectionString)
            .GetDatabase(databaseName)
            .GetCollection<T>(collectionName);
    }

    public T Find(ObjectId aggregateRootId)
    {
        return cache.GetOrAdd(
            key: aggregateRootId, 
            valueFactory: key => findById(key));
    }

    private T findById(ObjectId aggregateRootId)
    {
        return collection
            .Find(Builders<T>.Filter
                .Eq(x => x.Id, aggregateRootId))
            .SingleOrDefault();
    }

    public void SaveChanges()
    {   
        var writeModels = generateWriteModels();
        collection.BulkWrite(writeModels);
    }        

    private IEnumerable<WriteModel<T>> generateWriteModels()
    {
        List<WriteModel<T>> writeModels = new List<WriteModel<T>>();

        foreach (var cached in cache)
        {
            if (cached.Value != null)
            {
                if (cached.Value.UpdateDefinition != null)
                {   
                    writeModels.Add(new UpdateOneModel<T>(
                        filter: Builders<T>.Filter.Eq(x => x.Id, cached.Value.Id),
                        update: cached.Value.UpdateDefinition){ IsUpsert = true });
                    cached.Value.UpdateDefinition = null;
                }
            }
        }

        return writeModels;
    }
}

通过此实现,您可以与 Aggregate(UpdateDefinition<T> component) 进行交互AggregateRoot<T>的方法|直接在实现中使用基类(注意不要在 setter 上使用它——BsonSerializer 也使用 setter)。 Repository<T> 将消耗更改.

如果你想让你的领域模型尽可能地与商店实现分离,你可以构建一个等价于 MongoActionWrapper<TCollection> 的模型。作为聚合的包装器。这些包装器可以将聚合方法与 Aggregate(UpdateDefinition<T> component) 一起使用使更新定义与对聚合所做的更改保持同步。

关于C# Mongodb 驱动程序 : Translate Action into an UpdateDefinition,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40343759/

相关文章:

c# - 在回发之前运行 Javascript 函数

c# - 是否有 la Gavoille 等人的带有距离标记的最短路径算法的开源实现?

c# - WPF 在 Closing 事件中隐藏一个窗口防止应用程序终止

node.js - 如何获得 Mongoose 模型的所有计数?

java - MongoDB 3 Java检查集合是否存在

c# - 如何将 IndexOf 与 mongodb c# 中的 Builders 过滤器一起使用

c# - winforms c# 中的静态属性

node.js - 如何构建查询以将父文档的字段与嵌入数组文档的字段相关联。使用 MongoDB 聚合运算符

MongoDB C# 删除不起作用

c# - MongoDB。索引超出范围