Сегодня я узнал 05/05/2022
- Репозиторий
- Сценарий
- Реализация
Репозиторий
Вон Вернон в своей книге «Реализация проектирования, ориентированного на домены
определяет репозитории как:
Под хранилищем обычно понимается место хранения, которое обычно считается местом безопасности или сохранности хранящихся в нем предметов. Когда вы храните что-то в хранилище, а затем возвращаетесь, чтобы получить это, вы ожидаете, что оно будет в том же состоянии, в котором было, когда вы его туда положили. В какой-то момент вы можете решить удалить элемент, хранящийся в хранилище
ВЕРНОН, Вон. Реализация проектирования, ориентированного на доменЭти объекты похожи на коллекции по персистентности. Каждый постоянный тип Aggregate будет иметь Repository. В общем, между типом агрегата и хранилищем существует связь один-к-одному
ВЕРНОН, Вон. Реализация проектирования, ориентированного на домен
То есть, для каждого агрегата у нас есть только одно хранилище, так что если, например, мы вернемся к примеру агрегата, который я приводил в статье о сервисах в DDD
Для этого совокупного клиента будет создано только одно хранилище, которое будет содержать поля клиента И поля адреса, нет необходимости создавать таблицу для Address, поскольку домен приложения отличается от домена инфраструктуры.
Не проблема реализовать базу данных, думая о домене, проблема в том, чтобы реализовать домен, думая о базе данных.
Сценарий
Представьте себе сущность order, где каждый заказ должен иметь связанные с ним элементы, и в этой сущности нам также нужно сохранить id пользователя, который сделал заказ, и продукт, который связан с элементом заказа.
Однако, в конечном итоге, наша совокупность будет такой:
Реализация
Для создания хранилища нашего агрегата заказов нам изначально понадобятся две модели, модель OrderItem и модель Order. Мы создадим две таблицы для каждой базы данных, помня, что хранилище соответствует агрегату, но хранилище не имеет отношения 1 к 1 с таблицей в базе данных
(ps: модель была сделана с помощью sequelize, но используемая ORM не имеет большого значения, она может быть реализована с любой):
order-items.model.ts
@Table({
tableName: 'orders_items',
timestamps: false
})
export class OrderItemModel extends Model{
@PrimaryKey
@Column
declare id: string;
@ForeignKey(() => ProductModel)
@Column({allowNull: false})
declare product_id: string;
@BelongsTo(() => ProductModel)
declare product: ProductModel;
@ForeignKey(() => OrderModel)
@Column({allowNull: false})
declare order_id: string;
@BelongsTo(() => OrderModel)
declare order: OrderModel;
@Column({allowNull: false})
declare quantity: number;
@Column({allowNull: false})
declare name: string;
@Column({allowNull: false})
declare price: number;
}
order.model.ts
@Table({
tableName: 'orders',
timestamps: false
})
export class OrderModel extends Model{
@PrimaryKey
@Column
declare id: string;
@ForeignKey(() => CustomerModel)
@Column({allowNull: false})
declare customer_id: string;
@BelongsTo(() => CustomerModel)
declare customer: CustomerModel;
@HasMany(() => OrderItemModel)
declare items: OrderItemModel[]
@Column({allowNull: false})
declare total: number;
}
После объявления моделей мы можем создать хранилище:
export class OrderRepository{
async create(entity: Order): Promise<void> {
await OrderModel.create({
id: entity.id,
customer_id: entity.customer_id,
total: entity.total(),
items: entity.items.map(item => ({
id: item.id,
name: item.name,
price: item.price,
quantity: item.quantity,
product_id: item.productId,
}))
},
{
include: [{model: OrderItemModel}]
})
}
}
Хранилище Orders нам нужно только потому, что оно заботится о сохранении элементов в таблице order-items, когда мы создаем новый заказ.
Я все еще изучаю DDD, и если вы хотите увидеть код лучше, вы можете взглянуть на этот репозиторий