2016-10-31 5 views
1

私はmongodbのアップデートを一般化しようとしています。 EntityFrameworkを使用すると、これは変更トラッキングを持つので非常に簡単です。したがって、ビジネスロジックとデータベース固有の操作を分離できます。 MongoDbに関しては、ドキュメントの更新を行うためにこれらのUpdateDefinitionsを作成する必要があるので、簡単ではありません。C#Mongodbドライバ:アクションをUpdateDefinitionに変換する

これを模倣する簡単な方法はReplaceOneAsyncですが、複数の当事者が同時に自分のコレクションに書き込むことができるので、これはオプションではありません。私は例えば、アプリケーション内でチャットシステムに使用しています。

は、私はこのような何かやってみたかった:

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

    public Action<TCollection> UpdateAction { get; } 
} 

をそして私は私のMongoRepositoryを持っている:私は代わりにUpdateDefinitionのコレクションでアクションを実行したいと思います

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に変換します。

これは、私がmongodbにとどまっていないように、リスト(またはデータを保存したい他のコレクション)に同じアップデートを適用できるようにします。

私の唯一の解決策は、私のUpdateActionを更新を説明するオブジェクトのようにしてから、mongodbで永続化したいときにこれらのオブジェクトを翻訳することです。このようにして、それらをアクションに変換して、自分のコレクションや他のDBを選択することができます。

私はここでオプションが不足しているので、誰かがアイデアを持っていることを願っています。

答えて

0

は、私はあなたがアクションデリゲートでこれを行う方法がわからないですが、あなたは、単一のAggregateRoot上で複数の同時書き込みとリードスルー、ライトスルーキャッシュのようEntityFrameworkを再現したい場合、あなたはこのように気にいらを試すことができます。

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

この実装では、あなたが(それを使用しての外に見実施に直接AggregateRoot<T>基底クラスのメソッドAggregate(UpdateDefinition<T> component)と対話することができますsetters - BsonSerializerはセッターも使用します)。変更はRepository<T>によって消費されます。

ドメインモデルを店舗の実装からできるだけ分離したい場合は、MongoActionWrapper<TCollection>の同等物を集約のラッパーとして作成できます。これらのラッパーは、集計メソッドをAggregate(UpdateDefinition<T> component)と共に使用して、更新定義を集約に対して行った変更と同期させておくことができます。

関連する問題