Data Layer: Creating the Entities
To start using SOKit functionalities in our Quarkus project, we first need to define the entities representing our data model.
It's essential to have a clear understanding of the data model that our application will manage. Once that's clear, we can proceed to create the entities.
The database doesn’t have to be "real" during the initial development phase. Our project already includes Flyway setup under the resources folder, but for simplicity, we can disable it during development and use Hibernate ORM in update mode. To do this, set the following properties in your .properties file:
%dev.quarkus.hibernate-orm.database.generation=update
%dev.quarkus.flyway.active=false
The json below represents the data model of our application. For more details go to the Use Case section.
{
"companyName": "",
"legalForm": "",
"establishedDate": "",
"capital": 0,
"employees": 0,
"phone": "",
"email": "",
"vatNumber": "",
"remark": "",
"type": {
"code": "",
"description": ""
},
"address": {
"street": "",
"city": "",
"state": "",
"zip": ""
},
"website": "",
"shareholders": [
{
"id": "",
"firstName": "",
"lastName": "",
"phone": "",
"email": "",
"shares": 0,
"percentage": 0.0,
}
]
}
Since we have two roles (OFFICER and COMPANY), fields like vatNumber might be editable or visible only by certain users depending on their role.
Designing the Entities
Under the data module of the project, we will define two main entities: CompanyEntity and ShareholderEntity. The CompanyType and Address will be embedded classes.
package com.dev.registration.company.data;
import jakarta.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import com.strategyobject.sokit.extensions.document.api.entities.DocumentEntity;
@Entity
@Table(name = "TBL_COMPANY")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class CompanyEntity extends DocumentEntity implements Serializable {
private String companyName;
private String legalForm;
private LocalDate establishedDate;
private BigDecimal capital;
private Integer employees = 0;
@Embedded
private CompanyType type;
private String creatorSubject;
private String phone;
private String email;
private String vatNumber;
private String remark;
@Embedded
private CompanyAddress address;
private String website;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "parent")
private Set<ShareholderEntity> shareholders;
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object o) {
return super.equals(o);
}
}
Why Extend DocumentEntity? Because CompanyEntity is the root document of our domain. It inherits useful fields like id and ddt (document date) which help maintain historical records. Alternatively, you could extend DocumentBaseEntity (more in the advanced guide).
We use @Embedded for CompanyType and CompanyAddress because these are reusable, self-contained components that do not need separate identities.
package com.dev.registration.company.data;
import jakarta.persistence.Embeddable;
import java.io.Serializable;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Embeddable
public class CompanyType implements Serializable {
private String code;
private String description;
}
The CompanyAddress class is nearly identical to CompanyType in terms of structure and benefits. Using embedded classes reduces database complexity and avoids extra joins.
package com.dev.registration.company.data;
import jakarta.persistence.Embeddable;
import java.io.Serializable;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Embeddable
public class CompanyAddress implements Serializable {
private String street;
private String city;
private String state;
private String zip;
}
package com.dev.registration.company.data;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import com.strategyobject.sokit.extensions.core.exceptions.dto.SubElement;
@Entity
@Table(name = "TBL_SHAREHOLDER")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ShareholderEntity extends SubElement implements Serializable {
@Id
@Column(name = "SHAREHOLDER_ID", nullable = false, updatable = false)
private String id;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "DOCUMENT_ID", referencedColumnName = "DOCUMENT_ID")
private CompanyEntity parent;
private String firstName;
private String lastName;
private String phone;
private String email;
private Integer shares = 0;
private Double percentage;
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
ShareholderEntity that = (ShareholderEntity) o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
}
In this case, ShareholderEntity extends SubElement because it’s part of a list within the root DocumentEntity. This gives us access to the _eid field, a transient, additional identifier that’s not persisted in the database, but is useful for tracking elements (e.g. during validation or error handling).
What's Next
In the next chapter, we will explore how to manage entity states and perform operations on them.