Entities

An entity is used to represent a domain concept distinguished by an identity.
This identity must remain the same through the whole entity lifecycle.

Characteristics

Entities represent a thread of continuity and identity, going through a lifecycle, though their attributes may change. They are not defined primarily by their attributes but by their identity that stays the same through time and across distinct representations.

Identity

The identity of an entity must be unique and immutable. It must be chosen carefully and well defined in the model. Identification can come from:

  • The outside: a user of the system can provide the identity, handling the uniqueness himself.
  • The inside: the entity can generate its own identity using an algorithm.
  • An identity generator, like a database sequence.

It is often a good idea to use value objects as identifiers, particularly in the case of a composite identity. Its consistency and immutability can then be delegated to the value object.

Behavior

Entities should not be merely holders of attributes, but should also contain the behavior that is directly relevant to them. Do not create entities with only getters and setters but add methods with meaningful names, implementing domain behavior.

When the behavior does not fit naturally into a specific entity, for instance if multiple entities are involved, you move the behavior to domain services.

Declaration

To declare an entity with the business framework, you have two alternatives.

Extend the BaseEntity class:

public class SomeEntity extends BaseEntity<SomeEntityId> {
    @Identity
    private SomeEntityId id;

    public SomeEntity(SomeEntityId id) {
        this.id = id;
    }

    // Other methods
}

By extending BaseEntity, you will have a default implementation of the equals() and hashCode() methods, consistent with the definition of an entity. A toString() method is also provided by default.

  • If the identity is in a field named id, it will be automatically discovered.
  • Otherwise, you can mark the identity field with the @Identity annotation.
  • Alternatively you can override the getId() method to return the identity.

Implement the Entity interface:

public class SomeEntity implements Entity<SomeEntityId> {
    private SomeEntityId id;

    public SomeEntity(SomeEntityId id) {
        this.id = id;
    }
    
    public int hashCode() {
        // TODO: implement using identity attribute only
    }

    public boolean equals() {
        // TODO: implement using identity attribute only
    }

    @Override
    public SomeEntityId getId() {
        return this.id;
    }
    
    // Other methods
}

Implementing Entity allows you to fully control the inheritance of your entity. However, you will have to implement equals() and hashCode() methods yourself, consistently with the definition of an entity (i.e. based on the identity only).

You must implement the getId() method as the framework will often need to retrieve the entity identity.

Example

public class Customer extends BaseEntity<CustomerId> {
    private final CustomerId id;
    private String name;
    private String email;
    
    public Customer(CustomerId id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
    
    public void changeEmail(String newEmail) {
        if (!isEmailValid(newEmail)) {
            throw new CustomerException("Invalid email: " + newEmail);
        }
        email = newEmail;
    }
    
    public void changeName(String newName) {
        if (newName.isEmpty()) {
            throw new CustomerException("Name cannot be blank");
        }
        name = newName;
    }
    
    // other methods 
}

Notice:

  • How the identity is defined as an immutable value object and cannot be changed by external objects.
  • How method names have meaningful names and implement domain behavior.
   

On this page


Edit