В DDD
-проекте, в который я участвую, мы ищем несколько удобных решений для сопоставления entity objects
с domain objects
и наоборот.
Разработчики этого проекта полностью согласились отделить модель предметной области от модели данных. Уровень данных использует JPA (Hibernate)
в качестве технологии персистентности.
Поскольку мы все считаем, что персистентность - это деталь реализации в DDD, с точки зрения разработчиков, мы все ищем для наиболее подходящего решения в каждом аспекте приложения.
Наибольшую проблему мы имеем, когда aggregate
, содержащий список entities
, сопоставляется с JPA entity
, который в его Ход содержит отношение one-to-many
.
Взгляните на пример ниже:
Модель домена
public class Product extends Aggregate {
private ProductId productId;
private Set<ProductBacklogItem> backlogItems;
// constructor & methods omitted for brevity
}
public class ProductBacklogItem extends DomainEntity {
private BacklogItemId backlogItemId;
private int ordering;
private ProductId productId;
// constructor & methods omitted for brevity
}
Модель данных
public class ProductJpaEntity {
private String productId;
@OneToMany
private Set<ProductBacklogItemJpaEntity> backlogItems;
// constructor & methods omitted for brevity
}
public class ProductBacklogItemJpaEntity {
private String backlogItemId;
private int ordering;
private String productId;
// constructor & methods omitted for brevity
}
Репозиторий
public interface ProductRepository {
Product findBy(ProductId productId);
void save(Product product);
}
class ProductJpaRepository implements ProductRepository {
@Override
public Product findBy(ProductId productId) {
ProductJpaEntity entity = // lookup entity by productId
ProductBacklogItemJpaEntity backlogItemEntities = entity.getBacklogItemEntities();
Set<ProductBacklogItem> backlogItems = toBackLogItems(backlogItemEntities);
return new Product(new ProductId(entity.getProductId()), backlogItems);
}
@Override
public void save(Product product) {
ProductJpaEntity entity = // lookup entity by productId
if (entity == null) {
// map Product and ProductBacklogItems to their corresponding entities and save
return;
}
Set<ProductBacklogItem> backlogItems = product.getProductBacklogItems();
// how do we know which backlogItems are: new, deleted or adapted...?
}
}
Когда ProductJpaEntity
уже существует в DB
, мы нужно обновить все. В случае обновления ProductJpaEntity
уже доступен в Hibernate PersistenceContext
. Однако нам нужно выяснить, какие ProductBacklogItems
изменены.
В частности:
ProductBacklogItem
можно было бы добавить к Collection
ProductBacklogItem
мог быть удален из Collection
Каждый ProductBacklogItemJpaEntity
имеет Primary Key
, указывающий на ProductJpaEntity
. Кажется, что единственный способ обнаружить новые или удаленные ProductBacklogItems
- сопоставить их с Primary Key
. Однако первичные ключи не принадлежат модели домена ...
Также существует возможность сначала удалить все ProductBacklogItemJpaEntity
экземпляров (которые присутствуют в БД) из ProductJpaEntity
, flu sh в БД, создайте новые ProductBacklogItemJpaEntity
экземпляры и сохраните их в БД. Это было бы плохим решением. Каждое сохранение Product
приведет к нескольким операторам delete
и insert
в БД.
Какое решение существует для решения этой проблемы, не жертвуя при этом слишком многими жертвами в модели Domain & Data?