2016-10-31 6 views
1

Мы недавно начали использовать шаблон репозитория и совокупный корневой шаблон. Все это хорошо работает, когда я отслеживаю изменения с помощью EntityFramework, и я могу вызвать SaveChanges, когда я закончил работу над своей совокупностью.Образец репозитория и совокупный корневой шаблон. Как сделать SaveChanges в репозитории?

Теперь моя проблема в том, что я также хочу использовать этот шаблон с моим mongodb, но по своей природе mongodb не поддерживает отслеживание изменений. Рокинг моего собственного отслеживания изменений кажется немного излишним.

Моя проблема заключается в том, что я не могу работать с моей сущностью в связанном агрегате, а затем использовать репозиторий, чтобы сохранить его обратно в mongodb. Я могу сделать это только в том случае, если я использую ReplaceOneAsync, который, похоже, не подходит, потому что это чат, который я создаю, и поэтому может иметь несколько операций записи от разных клиентов.

Я хотел бы иметь какое-то отслеживание изменений, которое позволит мне вызвать SaveChanges в репозитории с указанным агрегатом.

Ней некоторые псевдо-код, который пытается объяснить, что я хочу сделать:

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 Task<bool> SaveAsync(TAggregate aggregate) 
    { 
     var state = aggregate.GetState(); 
     foreach (var stateChange in state.Changes) 
     { 
      var change = stateChange.ToUpdateDefinition(); 
      await _mongoCollection.UpdateOneAsync<TCollection>(aggregate.GetSelector(), change); 
     } 

     return true; 
    } 

    public TAggregate GetMongoAggregate(Expression<Func<TCollection, bool>> selector) 
    { 
     var state = _mongoCollection.AsQueryable().SingleOrDefault(selector); 
     return new AggregateWithSelector(state, selector); 
    } 
} 

GetMongoAggregate будет реализована в конкретных версиях репозитория, но здесь для псевдо цели.

Надеюсь, кто-то может отправить меня в правильном направлении или дать мне несколько советов о том, как моделировать это.

+0

SaveChanges в EntityFramework посылает набор команд в транзакции в Sql БД (это единица работы образца) , Основное отличие MongoDB заключается в том, что он не поддерживает транзакции. Я думаю, что лучше найти подход, который хорошо работает с MongoDB. – rnofenko

ответ

1

Вот простой пример моей реализации (если вам нужен реальный пример, вы можете написать мне в частном порядке)

У меня есть коллекция MongoDB:

public class TestCollection 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

И я сделал следующий агрегатный корнем для коллекция:

public class TestCollectionAggregateRoot : IAgregateRoot, 
    IHasObserver<IMongoObserver<TestCollection>>, 
    IHasSelector<IMongoSelector<TestCollection>> 
{ 
    private readonly IMongoSelector<TestCollection> _selector; 
    private readonly IMongoObserver<TestCollection> _observer; 
    private string _name; 

    public TestCollectionAggregateRoot(TestCollection root, IMongoSelector<TestCollection> selector, IMongoObserver<TestCollection> observer) 
    { 
     _selector = selector; 
     _observer = observer; 
     _name = root.Name; 
    } 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      if (_name != value) 
      { 
       _name = value; 
       _observer.OnPropertyChanged(x=>x.Name, _name); 
      } 
     } 
    } 

    public IMongoObserver<TestCollection> Observer => _observer; 
    public IMongoSelector<TestCollection> Selector => _selector; 
} 

где

public interface IMongoObserver<TCollection> 
{ 
    void OnPropertyChanged<TField>(Expression<Func<TCollection, TField>> func, TField value); 

    UpdateDefinition<TCollection> Definition { get; } 
} 

public interface IMongoSelector<TCollection> 
{ 
    FilterDefinition<TCollection> Definition { get; } 
} 

Простая реализация для IMongoObserver:

public class MongoObserver<TCollection> : IMongoObserver<TCollection> 
{ 
    private volatile UpdateDefinition<TCollection> _definition; 

    public void OnPropertyChanged<TField>(Expression<Func<TCollection, TField>> func, TField value) 
    { 
     if (Definition != null) 
     { 
      _definition = Definition.Set(func, value); 
     } 
     else 
     { 
      _definition = Builders<TCollection>.Update.Set(func, value); 
     } 
    } 
    public UpdateDefinition<TCollection> Definition => _definition; 
} 

Простой пример Repository.SaveAsync (без InsertOneAsync)

public class Repository : IRepository<TestCollectionAggregateRoot> 
{ 
    private readonly IMongoCollection<TestCollection> _mongoCollection; 

    public Repository(IMongoCollection<TestCollection> mongoCollection) 
    { 
     _mongoCollection = mongoCollection; 
    } 

    public async Task<bool> SaveAsync(TestCollectionAggregateRoot aggregate) 
    { 
     var changes = aggregate.Observer.Definition; 
     var selector = aggregate.Selector.Definition; 

     await _mongoCollection.UpdateOneAsync(selector, changes); 
     return true; 
    } 
} 
+0

Я тоже думал об этом, но тогда возникает проблема со сложными типами, такими как массивы и объекты. Как вы обрабатываете обновление без замены всего массива или объекта? (Я нахожусь на своем мобильном телефоне, так что извините меня, если я что-то не замечаю) –

+0

Агрегатор знает об обновлении внутри, и мы можем использовать его, например, метод Push для изменения элементов в массиве корня. Основная идея, что агрегатор должен вернуть UpdateDefinition в SaveAsync, чтобы применить все обновления. –

+0

Но тогда вы связываете свой агрегат с реализацией db, чего я пытался избежать. Теперь вашему агрегату необходимо знать как единицу работы, так и наблюдателя. Если вы не загружаете свои собственные обновления db на основе наблюдателя, это не помогает мне с проблемой агрегата для SQL и mongo, имеющих разные реализации. –