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 extendsSimpleMongoRepository \<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
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 interfaceJpaRepository \<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
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
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.