Alanlarını uygulamak için CQRS kullanan büyük bir topluluk var. Benim hissim, deponuzun arayüzü onlar tarafından kullanılan en iyi uygulamalara benziyorsa, çok yoldan sapmayacaksınız.
Gördüklerime dayanarak ...
1) Komut işleyicileri genellikle toplamı bir depo yoluyla yüklemek için havuzu kullanır. Komutlar, toplamanın belirli bir örneğini hedefler; depo kökü kimliğe göre yükler. Görebildiğim gibi, komutların toplu bir koleksiyona karşı çalıştırıldığı bir durum yoktur (bunun yerine, önce toplamaların toplanmasını almak için bir sorgu çalıştırırsınız, ardından koleksiyonu numaralandırır ve her birine bir komut verirsiniz.
Bu nedenle, toplamı değiştireceğiniz bağlamlarda, deponun varlığı (yani toplam kök olarak) döndürmesini beklerim.
2) Sorgu işleyicileri toplamlara hiç dokunmaz; bunun yerine, toplanmaların / toplanmaların durumunu belirli bir zamanda tanımlayan değer nesnelerinin projeksiyonları ile çalışırlar. Öyleyse AggregateDTO yerine ProjectionDTO'yu düşünün ve doğru fikre sahipsiniz.
Toplamaya karşı sorgular çalıştıracağınız, görüntülemeye hazırlayacağınız bağlamlarda, bir varlık yerine döndürülen bir DTO veya bir DTO koleksiyonu görmeyi beklerim.
Tüm getCustomerByProperty
aramalarınız bana sorgular gibi geliyor, bu yüzden ikinci kategoriye girecekler. Büyük olasılıkla koleksiyonu oluşturmak için tek bir giriş noktası kullanmak istiyorum, bu yüzden eğer
getCustomersThatSatisfy(Specification spec)
makul bir seçimdir; sorgu işleyicileri daha sonra verilen parametrelerden uygun belirtimi oluşturacak ve bu belirtimi depoya geçirecektir. Dezavantajı, imzanın havuzun hafızada bir koleksiyon olduğunu düşündürmesidir; depo sadece ilişkisel bir veritabanına karşı bir SQL deyimi çalıştırmanın bir soyutlama ise yüklemin size çok şey aldığı açık değildir.
Yine de yardımcı olabilecek bazı desenler var. Örneğin, belirtimi elle oluşturmak yerine, depoya kısıtlamaların bir açıklamasını iletin ve ne yapılacağına karar vermek için havuzun uygulanmasına izin verin.
Uyarı: java like typing tespit
interface CustomerRepository {
interface ConstraintBuilder {
void setLastName();
void setFirstName();
}
interface ConstraintDescriptor {
void copyTo(ConstraintBuilder builder);
}
List<CustomerProjection> getCustomersThatSatisfy(ConstraintDescriptor descriptor);
}
SQLBackedCustomerRepository implements CustomerRepository {
List<CustomerProjection> getCustomersThatSatisfy(ConstraintDescriptor descriptor) {
WhereClauseBuilder builder = new WhereClauseBuilder();
descriptor.copyTo(builder);
Query q = createQuery(builder.build());
//...
}
}
CollectionBackedCustomerRepository implements CustomerRepository {
List<CustomerProjection> getCustomersThatSatisfy(ConstraintDescriptor descriptor) {
PredicateBuilder builder = new PredicateBuilder();
descriptor.copyTo(builder);
Predicate p = builder.build();
// ...
}
class MatchLastName implements CustomerRepository.ConstraintDescriptor {
private final lastName;
// ...
void copyTo(CustomerRepository.ConstraintBuilder builder) {
builder.setLastName(this.lastName);
}
}
Sonuç olarak: bir agrega sağlama ve bir DTO sağlama arasındaki seçim, tüketicinin onunla ne yapmasını beklediğinize bağlıdır. Benim tahminim, her bağlam için bir arabirimi destekleyen somut bir uygulama olurdu.
GetCustomerByName('John Smith')
Veritabanınızda yirmi John Smith varsa ne dönecektir? Görünüşe göre hiç kimsenin aynı ada sahip olmadığı varsayılıyor.