Repository

When aggregate persistence support is enabled, the SDK provides access to the database through a repository. Using this, the connection to the underlying database is automatically established. As Aggregates are considered as a persistable unit, a repository class is generated for each root entity which allows to read, save and delete data from the database.

Depending on your chosen database type "MongoDB" or "RDBMS", the base class of that repository will vary.

MongoDB persistence

  • Each Root Entity instance will be saved into a Mongo DB Collection.

  • The Repository Class through its inheritance chain extends SimpleMongoRepository \<T, ID\>.

  • The SimpleMongoRepository provides access to several functionalities such as findBy, findAll, count, save, delete....etc.

  • You can directly inject root entity repository or use it using repo which is a repository facade that is available in commands, domain services, external entities and agents base classes.

Example of repository usage for different database operations.

// Build a credit card root entity that exists in a domain namespace prefixed by cc.
CreditCard creditCard = this.entityBuilder.getCc().creditCard()
    .setBankName("MyBank")
    .setCardType(CardType.debit)
    .setCustomer(customer)
    .setIssueDate(OffsetDateTime.now())
    .build();

// Save a credit card root entity.
creditCard = this.repo.getCc().getCreditCard().save(creditCard);

// Retrieve all credit card root entities
List<CreditCard> cards = this.repo.getCc().getCreditCard().findAll();

// Retrieve all credit card root entities filtered by CardType
ExampleMatcher matcher = ExampleMatcher.matchingAll().withIgnorePaths("BankName", "Customer", "IssueDate");
Example<CreditCard> example = Example.of(creditCard, matcher);

List<CreditCard> queryResult = repo.getCc().getCreditCard().findAll(example);

// Update credit card root entity
creditCard.setCardType(CardType.credit);
repo.getCc().getCreditCard().save(creditCard);

// Delete credit card root entity
repo.getCc().getCreditCard().delete(creditCard);

//Count all credit card root entities
long count = this.repo.getCc().getCreditCard().count();

Example of using inside a command implementation using declared repository from command base class.

//... imports

@Service
public class CardCommand extends CardCommandBase {

  private static Logger log = LoggerFactory.getLogger(CardCommand.class);
  
  public CardCommand(DomainEntityBuilder entityBuilder, DomainEventBuilder eventBuilder, EventProducerService eventProducer, Repository repo) {
    super(entityBuilder, eventBuilder, eventProducer, repo);
  }


  @Override
  public Card createCreditCard(CreditCard creditCard) throws CreditCardCreationError {

    log.info("CardCommands.createCreditCard()");
        // ..... command logic

        // Using this.repo to find and save an updated Card root entity
        try {

            Optional<Card> cardRootEntity = this.repo.getCc().getCard().findById(creditCard.getId());
        
          // Update card if it exists
          if(cardRootEntity.isPresent()){

            cardRootEntity.setActive(true);

            log.info("Updated Credit Card Root Entity with Id {}", cardRootEntity.getId());
            
            // Save updated card
            this.repo.getCc().getCard().save(cardRootEntity);
            } else {
              throw CardNotFoundException("Could not find card with Id {}", creditCard.getid());
            }

    } catch(Exception e) {
      // ... Exception handling logic
    }

    return cardRootEntity;
  }

Example of injecting and using CardRepository in a mapper utility.

//... imports

// Importing *CardRepository*
import de.knowis.cards.sdk.domain.card.repository.CardRepository;

@Service
public class Mapper {

  private static Logger log = LoggerFactory.getLogger(Mapper.class);

  // Injecting *CardRepository*
  @Autowired
  private CardRepository cardRepo;

  @Override
  public Optional<Card> mapToRootEntity(String cardId){
        
        Optional<Card> card= cardRepo.findById(cardId);

    return card;
  }

For more information about the functions of generated repositories that is inherited from SimpleMongoRepository See Official Spring Documentation

Tip:

Repository find / count operations on a Root Entity that has child entities, will include these children as well.

MongoDB inheritance support

  • Within MongoDB Persitence support, multiple inheritance is supported through interfaces and concrete classes.

  • Root Entity will have a corresponding interface that extends all its modelled parents, that interface will be implemented by a single concrete class.

public interface RelationRole extends ManagerialRelation, MarketingRelation {

  String getRoleType();

  void setRoleType(String roleType);

  BigDecimal getShare();

  void setShare(BigDecimal share);

}
  • Finally the concrete class that represents that entity will implement that interface (i.e. will have properties of its own and those inherited from parent entities).
public  class RelationRoleEntity extends EntityBase implements RelationRole {

  public RelationRoleEntity(){}

  @Field(name="roleType")
  @NotEmpty
  private String roleType;
  
  @Field(name="share", targetType = FieldType.DECIMAL128)
  private BigDecimal share;
  
  RelationRoleEntity(RelationRoleBuilder builder) {
    this.roleType = builder.roleType;
    this.share = builder.share;
    
  }

RDBMS persistence

  • The Repository Interface through its inheritance chain extends interface JpaRepository \<T, ID\>

  • The JpaRepository provide access to several functionalities such as findBy, findAll, count, save, delete....etc.

  • You can directly inject root entity repository or use it using repo which is a repository facade that is available in commands, domain services, external entities and agents base classes.

Example of repository usage for different database operations.

    // Build a credit card root entity that exists in a domain namespace prefixed by cc.
    CreditCardEntity creditCard = this.entityBuilder.getCc().getCreditCard()
        .setBankName("MyBank")
        .setCardType(CardType.debit)
        .setCustomer(customer)
        .setIssueDate(OffsetDateTime.now())
        .build();

    // Save a credit card root entity.
    creditCard = this.repo.getCc().getCreditCard().save(creditCard);

    // Retrieve all credit card root entities
    List<CreditCardEntity> cards = this.repo.cc.creditCard.findAll();

    // Update credit card root entity
    creditCard.setCardType(CardType.credit);
    this.repo.getCc().getCreditCard().save(creditCard);

    // Delete credit card root entity
    this.repo.getCc().getCreditCard().delete(creditCard);

    //Count all credit card root entities
    long count = this.repo.getCc().getCreditCard().count();

Example of using inside a command implementation using declared repository from command base class.

//... imports

@Service
public class CardCommand extends CardCommandBase {

  private static Logger log = LoggerFactory.getLogger(CardCommand.class);
  
  public CardCommand(DomainEntityBuilder entityBuilder, DomainEventBuilder eventBuilder, EventProducerService eventProducer, Repository repo) {
    super(entityBuilder, eventBuilder, eventProducer, repo);
  }

  @Override
  public Card createCreditCard(CreditCard creditCard) throws CreditCardCreationError {

    log.info("CardCommands.createCreditCard()");
        // ..... command logic

        // Using this.repo to find and save an updated Card root entity
        try {

            Optional<CardEntity> cardRootEntity = 
            this.repo.getCc().getCard().findById(creditCard.getId());
        
          // Update card if it exists
          if(cardRootEntity.isPresent()){

            cardRootEntity.setActive(true);

            log.info("Updated Credit Card Root Entity with Id {}", cardRootEntity.getId());
            
            // Save updated card
            this.repo.getCc().getCard().save(cardRootEntity);
            } else {
              throw CardNotFoundException("Could not find card with Id {}", creditCard.getid());
            }

    } catch(Exception e) {
      // ... Exception handling logic
    }

    return cardRootEntity;
  }

Example of injecting and using CardRepository in a mapper utility.

//... imports

// Importing *CardRepository*
import de.knowis.cards.sdk.domain.card.repository.CardRepository;

@Service
public class Mapper {

  private static Logger log = LoggerFactory.getLogger(Mapper.class);

    // Injecting *CardRepository*
    @Autowired
    private CardRepository cardRepo;

  @Override
  public Optional<CardEntity> mapToRootEntity(String cardId){
        
        Optional<CardEntity> card= cardRepo.findById(cardId);

    return card;
  }

For more information about the functions of generated repositories that is inherited from JpaRepository See Official Spring Documentation

Tip:

Repository find / count operations on a Root Entity that has child entities, will include these children as well.

RDBMS inheritance support

  • Inheritance is one of the key concepts in Java, and it's used in most domain models.

  • SQL doesn't support this kind of relationship, SDK used the JPA single table inheritance strategy to map inheritance between Entities.

  • Within RDBMS multiple inheritance is not supported, Root Entity can only have one parent.

  • Each Root Entity will have an associated table name.

  • Root Entities that have parent(s), their upmost parent table name will be used as this is the JPA implementation for single table inheritance strategy.

Single table inheritance strategy

  • Single Table inheritance: the simplest and typically the best performance when doing queries.
  • Single Database Table: will be used to store every attribute of every class in the hierarchy.
  • Discriminator Column: used to determine which class the row belongs to, each class in the hierarchy defines its own unique discriminator value.

Entity inheritance model example


entity inheritance model example

Single table inheritance example


single table inheritance example

Mapping in RDBMS

Unlike MongoDB persistence support see MongoDB persitence support, where there is only db references used See Official mongo DBRef documentation

RDBMS have relationships between tables, below is how the relationships between entities is reflected in persistence.

Root Entity

Mapped to its own tables with support for One-To-Many and One-To-One Foreign Key relationships with other root entities.

(Value) Entity

Common use case as value objects, input to commands, services, etc.

If modelled as a property of a root entity, its data will be embedded in the root entity's table. In case of a collection (list of value entities), a collection table will be created and linked with root entity.

External Entity

Common use case as reference to an entity that resides outside the domain (or even within an external system). The same embedded strategy that applies to value entities will be applied here.

Mapping example

Below is a representation of an entity hierarchy and how its mapped into a DB2 RDBMS.


Entity examples

Mapping example