Задать свойство Updates для объекта при использовании EF Core и DDD - PullRequest
0 голосов
/ 20 мая 2019

У моей сущности есть это:

public DateTime UpdatedAt { get; private set; }

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

private void updateTimeStamp() => UpdatedAt = DateTime.UtcNow;

Но тогда мне нужно запомнитьвызывать его в каждом методе, который мутирует сущность, например:

public void addOrder(Order order) {
  //blah blah
  updateTimeStamp();     // <----- musn't forget this!
}

Я часто забываю вызывать этот метод, поэтому я думаю об альтернативах.Я не знаю, что лучше, или если есть что-то, что я не учел.

Вариант 1: инициализировать свойство

public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;

Проблема: это будетустанавливается каждый раз, даже если я не хочу обновлять сущность.

Опция 2: атрибуты

[UpdateTimestamp]
public void addOrder(Order order) {
  //blah blah
}

Проблема: это не улучшаетситуация, в основном, такая же, как исходная проблема.

Вариант 3: автоматическое обновление в context.SaveChanges()

ChangeTracker.Entries()
  .Where(e => e.Entity is MyEntity)
  .Where(e => e.State == EntityState.Modified)
  .Where(e => e.Entity as MyEntity)
  .ToList()
  .ForEach(e => { e.UpdatedAt = DateTime.UtcNow; });

Проблема: UpdatedAt теперь нужна общедоступнаясеттер.Это нарушает принципы DDD.Это самый простой вариант, но это означает, что я должен отказаться от DDD "всегда действительным".

Опция 3: то же, что 3, но с использованием отражения
Подобно варианту 3, я мог бы использоватьотражение, чтобы изменить свойство, даже если у него есть частный сеттер.Это достаточно легко сделать, и тот факт, что это отражение и «медленный», не имеет большого значения, так как время будет незначительным по сравнению с записью в базу данных.

Проблема: сделать изменения в инфраструктуре, а недомен просто кажется неправильным.

В противном случае это довольно хороший выбор.Это не чистый DDD, но, по крайней мере, он позволяет мне защитить инварианты сущности.

Вариант 4: разгрузка на провайдера БД или самой БД

builder.Property(e => e.UpdatedAt).ValueGeneratedOnUpdate();
// or
builder.Property(e => e.UpdatedAt).HasComputedColumnSql("GETDATE()");

Проблема:не работает для всех провайдеров (не работает для меня, потому что я использую Npgsql, который не поддерживает вычисляемые столбцы).Также это перемещает проблему в инфраструктуру и из домена.Поэтому я чувствую, что снова ломаю DDD.

Итак ... что-то я забыл?Если вы делаете DDD, как вы справляетесь с этим?

1 Ответ

1 голос
/ 20 мая 2019

Как вы уже указали, вариант 1 не подходит, так как вы можете просто получить Заказ, не обновляя ничего, и дата все равно изменится.

Вариант 2, вероятно, также нарушит принципы DDD, поскольку вы могли бы изменить свойЗаказывайте и не меняйте дату обновления до тех пор, пока вы не нажмете этот конкретный метод.

Все, что вам осталось, это вариант 3, я полагаю, он менее плох, учитывая принципы DDD, а также наиболее удобен в использовании.Вы должны идти по этому пути.Просто создайте интерфейс с вашим свойством updatedAt и методом updateTimeStamp и внедрите его в своих сущностях.Вероятно, вам следует создать базовый класс и реализовать этот метод.Затем получите измененные записи в методе SaveChanges, как вы предложили, и используйте метод вместо свойства, чтобы избежать частной установки сеттера.

Существует 4-й вариант, в котором вы можете использовать классы отражения и прокси, но это будетдлинный выстрел только для того, что вы просите ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...