DDD: Aggregate and entities relationship - java

I read some of the publications and threads about DDD. There are many voices about connection between aggregate and entities. I understood that aggregate should be as simple as possible (one entity per aggregate). But what about situation when aggregate has collection of entities?
Let's say, we have one aggregate called "Month" which contains a collection of "Day" objects (that are domain entities, because they need an identity to be
distinguishable - to let aggregate know which "Day" to modify).
So I have two questions:
Is this a proper approach? Just a normal situation and I shouldn't be concerned?
What about "visibility" outside? In my approach, an aggregate is "package-private" to not let anyone use it in different parts of the system. But what about entities? Should they be visible just like Value Objects for different parts of the system? Or just create another VO to represent entities outside (for example: when entities are stored in events)?
Thank you for all the answers

Modeling days and months as entities depends a lot on the context. It might not be the best example to explain aggregates and entities but let's give it a try.
Let's assume that in our context a day can not exist on its own. It has to be within a month. If you want to refer to a day, you must specify the month first. That is how we use dates in real life, January 1st, May 8th ... Even though the days are entities they don't need a global uniques identifier. They only need an identifier within the month [1 .. 31].
Aggregates should be as small as possible however it is not a rule that you should only have one entity per aggregate. You just need to have an aggregate root (month) that has a unique identifier across all the systems. Within the aggregate, you can have entities(days) that have a unique identifier within the aggregate[1 .. 31]. If you want to refer to or access these entities you should always go through the aggregate root.

Aggregate, Entity and ValueObject
In my vision, an entity is a child with a name (Id) of an Aggregate which, in turn, is the Father with a name (Id).
An aggregate can have NO entity.
You can think well is an entity, NO: an entity exist ONLY within an Aggregate.
The entity (child) is a small aggregate (father) without other entities (children's).
Fathers and children can use transparent box (I don't have a better idea to translate the concept of ValueObject, sorry): when you create a transparent box you cannot change anything but you can read the content, if you want to update the box you MUST create a new one.
The aggregate is responsible for manage the entities, this means: add, update, remove and query.
If you want to talk (query) with an entity or entities you must ask the aggregate, consequentially, when you load the aggregate you MUST load all entities.
An aggregate can have multiple types of entities, how many? Well, this depends on you, on the design, and on the system.
Obviously, a big aggregate of many fields with many entities with each of them many rows maybe is not efficient, in this case, maybe you can choose the biggest entities and turn in Aggregates with or without children.
Pratical example
I wrote the example on csharp but is not much different from Java.
class Invoice : ValueObject
{
public string Number { get; private set; }
public DateTime Date { get; private set; }
public decimal TaxableAmount { get; private set; }
public decimal VatAmount { get; private set; }
public decimal TotalAmount => TaxableAmount + VatAmount;
public Invoice(string number, DateTime date, decimal taxableAmount, decimal
vatAmount)
{
// validation
Number = number;
[..]
}
}
class Taxonomy : Entity
{
public int Id {get; private set;}
public decimal Amount {get; private set;}
public string Classfication {get; private set;}
public Taxonomy(int id, decimal amount, string classification)
{
// validation
Id = id;
[..]
}
}
class SaleAggregate : AggregateRoot
{
private List<Taxonomy> _taxonomies;
public int Id {get; private set;}
public Invoice Invoice {get; private set;}
public IReadOnlyCollection<Taxonomy> Taxonomies => _taxonomies.AsReadOnly();
public SaleAggregate(int id, string number, DateTime date, decimal
taxableAmount, decimal vatAmount)
{
_taxonomies = new List<Taxonomy>();
// I prefer to pass ALWAYS primitive types to not rely on valueObject
// validation
Id = id;
Invoice = new Invoice(number, date, taxableAmount, vatAmount)
[..]
}
public void AddTaxonomy(int id, decimal amount, string classification)
{
// validation
_taxonomies.Add(new Taxonomy(id, amount, classification);
}
public void UpdateTaxonomy(int id, decimal amount, string classification)
{
// validation
var entity = _taxonomies.FirstOrDefault(p=> p.Id == id);
entity.Amount = amount;
entity.Classification = classification;
}
public void RemoveTaxonomy(int id)
{
// validation
var entity = _taxonomies.FirstOrDefault(p=> p.Id == id);
_taxonomy.Remove(entity);
}
public void UpdateVatAmount(decimal vatAmount)
{
// validation
Invoice = new Invoice(Invoice.Number, Invoice.Date,
Invoice.TaxableAmount, vatAmount);
}
}
Again: this is my vision about Aggregate, Entities, and ValueObject, other developers reading this can feel free to correct me.

Related

Creating a loose relationship between multiple objects that others can search on

I have a list of car manufacturers, models, and trims. Each of those objects has different attributes on them. Ex. car makers can have import vs domestic, sport vs luxery, etc. My current setup looks something like below,
public Manufacturer {
private String manufacturerName; //Getter&Setter as well
private List<Model> modelList; //Getter&Setter as well
//additional attributes
}
public Model {
private String modelName;
private List<Trim> trimList; //Getter&Setter as well
//additional attributes
}
public Trim {
private String trimType; //Getter&Setter as well
//additional attributes
}
public ContainerClass {
public List<Manufacturer> manufacturerList;
}
Now I can create the objects as Mazda, 3, Grand Touring and associate the objects in the list. But if someone comes along and just wants a car that has a sunroof, it feels like a waste to have to dig into every possible manufacturer and every model for that manufacturer to see if the trim has a sunroof attribute. Are there any strategies I could use to make this easier for developers, including myself?
Note: I am at a point where I don't have a database because I don't have real data to fill the database, this is a stop gap until I get that data later, so please don't just say "create a database" :). Also I am loading this information from an ExamplesTable object of JBehave.
You can filter the manufacturers by some sub-streams:
container.getManufacturerList().stream()
.filter(manufacturer ->
manufacturer.getModelList().stream().anyMatch(model ->
model.getTrimList().stream().anyMatch(trim ->
trim.getTrimType().equals("sunroof"))))
.collect(Collectors.toList());

How to optimize this OO design in Hibernate ORM?

Based on object-oriented approach, I write the following entities:
#Entity
public class Customer {
#Id
private String id;
#OneToMany
private List<Order> orders;
public BigDecimal getTotal() {
// iterate over orders and sum the total
BigDecimal total = BigDecimal.ZERO;
for (Order o: orders) {
total = total.add(o.getTotal());
}
return total;
}
... // getter & setter
}
#Entity
public class Order {
#Id
private String id;
private BigDecimal total;
...
}
I realized that when calling getTotal() method for a Customer, Hibernate will issue a SELECT * FROM Order query to retrieve all Orders. The number of Order will surely increase as years passed. I believe a SELECT SUM(o.total) FROM Order o will give a better performance, CMIIMW. I just don't know where should I put the query? Rules of object oriented design suggest that getTotal() should be part of Customer, but the framework I'm using (Spring Transaction) doesn't allow transaction in domain objects.
In the first case, select * from orders.
You are just getting the list of orders and you need to calculate the sum in Server side code with iterating over the orders.
In the second case, select sum(o.total) from orders where order.customer_ id = 1234;
Database is doing the calculation for you. In terms of performance also,
this is better.
Why the database needs to delegate to some upper layer, when It can do it.
So I suggest you with the second case only.
As per OO, It might suggest to encapsulate both properties and related methods.
But its a Domain Class, which gets directly mapped to fields in Database.
To separate Data Access Logic, We can have a separate layer i.e DAO and put the desired logic in it.

OOAD Design issue

I have two tables: tblCustomer, tblProduct:
tblCustomer:
Id: Integer, auto-increament
Name: Varchar(30)
....
tblProduct
Id: Integer, auto-increament
Name: Varchar(50)
customerId: Integer
....
And two classes: Customer, Product:
public class Product
{
private int id;
private int name;
/* Other stuffs */
}
public class Customer
{
private int id;
private String name;
private String phoneNumber;
/* get-set and others stuffs */
public static boolean add(Customer cus) {
/* This is for insert a customer to tblCustomer */
}
public boolean addProduct(Product pd) {
/* This is for insert a product to tblProduct with current customer Id */
}
}
When customer register account, it call:
Customer cus = new Customer(/* ... */);
Customer.add(cus);
and when customer buy a product:
Product pd = new Product(/* ... */);
currentCustomer.addProduct(pd);
But my teacher said it not correct in OOAD (and even OOP) because Customer.addProduct is operate on tblProduct table, is it right? What is good design for this case?
** Update: **
Product haven't a pre-defined yet, when a customer buy a product, the store will make it and delivery to customer, so two same products is rare happen, so is tblCustomerProduct need?
What your teacher probably means is that you need a third table, named something like "CustomerProduct". This table contains the links between customers and which products they've bought.
tblCustomerProduct:
Id: Integer, auto-increament
CustomerId: Varchar(30)
ProductId: Varchar(30)
so, when a customer buys a product, you add this data to the table CustomerProduct. This will remove redundant data and also make deletion alot easier
Your teacher is right. It is not good Design because A class that you create should be cohesive. So that it should be responsible for doing the things that it can do. Here in your product class you have added customer id which is essentially a bad practice because A customer may purchase multiple products. This design will fail in that case. And also Product class doesn't need to know anything about the customer. All it has to know about is itself.
The relation between customer and product is an association which can be expressed as "customer buys product". So that customer id should not be there in product table.
Regarding the currentCustomer.addProduct(pd); method, it is not well suited because it is more suitable to product class rather than customer class.
The simple solution to your problem can be create a new class which can relate product and the customer.
For e.g.
CustomerProduct
customerid
productid
Inside this class you can add method like "AddProductForCustomer" and can write your database logic which will maintain the consistency.
Hope this clears your doubt.
Add a DAO tier that will contain the logical part of the methods save, delete, update, etc.
Here is how I usually do:
basepackage.domain: contains all your entities (data only, no logical part - in your case Product and Customer)
basepackage.dao: contains all your DAOs, only used to access the data, basically one per entity, each one containing methods such as findAll() : List<E>, findOne(K id) : E, save(E e) : void, etc.
basepackage.service: contains all your services, the logical part of the app. The services are the only ones that are calling the DAOs.
basepackage.presentation (or basepackage.web for a webapp): contains the HMI/web services/... implementation.
In the table, the customer is assigned to a product, but in the method you give a customer and add a product.
So I would go for either a method pd.setCustomer(currentCustomer) instead of currentCustomer.addProduct(pd)
Or change the customer field in the product table to a products field in the customer table.

Need to know if each field has changed, how should I model this in Hibernate

So I have a class with three fields that maps to a table using hibernate
Class Widget
{
String field1;
String field2;
String field3;
}
On application startup a number of instances these widgets will be added to the database from an external files, but when I exit the application I need to know which (if any) of these fields have been changed by the user since the application was started, so the changes can be saved back to the files. I also need to store the original value for logging purposes.
I can't work whether I need a status field in the table or whether there is already a way of doing this using Hibernate/Database.
EDIT:A good solution to the program was given below . however the main reason I am using Hibernate is to reduce memory consumption so storing the original values when changed is not a good solution for me , I want everthing stored in the database. So I have create this new question How do I store a copy of each entity I add to database in Hibernate
Given an entity like the following you can track changes on one of it's field (while preserving its original value too).
#Entity
#Table(schema = "test", name = "test")
public final class Test {
private static final int ORIGINAL = 0;
private static final int CURRENT = 1;
private Integer id;
// holds the original and current state of the field
private final AtomicReferenceArray<String> field = new AtomicReferenceArray<>(2);
#Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Transient
public String getOriginalField() {
return field.get(ORIGINAL);
}
#Basic
public String getField() {
return field.get(CURRENT);
}
public void setField(String field) {
this.field.compareAndSet(ORIGINAL, null, field);
this.field.set(CURRENT, field);
}
#PreUpdate
public void preUpdate() {
System.out.format("Original: %s, New: %s\n", getOriginalField(), getField());
}
...
}
If there is a single row in a database like this:
id: 1
field: a
version: 2011-12-02 11:24:00
before the field gets updated (say, from a to b) you'll get the following output.
Original: d, New: b
The original value gets preserved even if the the entity is updated multiple times and both state can be accessed through the corresponding getters (getField and getOriginalField—you can get more creative than me in the naming :).
This way, you can spare yourself from creating version columns in your database and also can hide the implementation details from clients.
Instead of an AtomicReferenceArray you could use arrays, lists, etc, to track all changes like this way.
The #PreUpdate isn't necessary of course, but this way you can be notified of changes in the entity's state and atomically save the updated fields into file. There more annotations like these: see the documentation for javax.persistence for other annotation types.
If you are using MySql then you can get table's last update time from information_schema database like
SELECT UPDATE_TIME FROM `information_schema`.`tables`
WHERE TABLE_SCHEMA = 'dbName' AND TABLE_NAME = 'tableName'
Or else simple solution will be to add a column for update time stamp. By this you can even monitor which particular row has been updated.
If you need to synchronize with files as soon as you save into database, You can use the Hibernate event mechanism to intercept any save to database and save it to file, here's a sample doing that.

JPA 2.0 persisting property with no setter

I'm using JPA 2.0, more precisely Eclipselink. Here's my problem:
I have an entity that has a property like "isPaid". that property is the result of some calculations the entity performs with some of its other fields. since this is derived from other fields, the property does not have a setter method.
As an example, the getter is something like this:
public boolean isPaid() {
return this.totalAmount - this.amountPaid == 0;
}
that's just an example. The thing is, I want this property to be calculated and persisted, so i can do a jpql query like:
SELECT d FROM Debt d WHERE d.isPaid = true
Is this possible? Is there any workaround for this?.
I don't want to retrieve all entities to call this method and then filter those that return true.
Here are a couple of options:
1) Create a jpql query that directly does what you need:
select d from Debt d where (d.totalAmount - d.amountPaid) = 0
The benefits of the approach is that it is simple and will always work. The downside is that your query has to understand how the paid logic was calculated.
2) Create a persisted paid value that stores the calculated value:
#Basic
private boolean paid;
public boolean isPaid() {
return this.paid;
}
private void updateCalculations() {
this.paid = (this.totalAmount - this.amountPaid == 0);
}
// using int as example here
public void setTotalAmount(int totalAmount) {
this.totalAmount = totalAmount;
updateCalculations();
}
public void setAmountPaid(int amountPaid) {
this.amountPaid = amountPaid;
updateCalculations();
}
The benefit of this approach is that you will be able to create a jpql query that directly checks for the boolean value, i.e.,
select d from Debt d where d.paid = true;
Obviously, the downside to the approach is that you need to make sure to recalculate the value anytime you update the values. However, this can be alleviated if you only calculate it on access. Meaning that in your isPaid() method, you calculate the value, assign it to the paid attribute and then return the value. If you decide to go with this approach, you will need to add a #PrePersist and #PreUpdate method that performs the paid calculation and updates the paid attribute prior to the bean being persisted to the datastore (makes sure that the paid value is always covered.
If you use JPA annotations on your attributes themselves, you can have a getter without a setter and still be able to correctly retrieve and store the values in the database.
Seen this: Mapping calculated properties with JPA ?
Basically you need a setter one way or the other in order to make JPA happy.

Categories

Resources