According to the clean architecture:
Your Entity objects should be plain old objects that have no dependencies on frameworks or databases or other complications.
As we see in Uncle Bob’s diagram, the gateway (Repository) interface is coupled to Domain Entities.
At this point, I faced the problem because JpaRepositoty<T, ID>
works only with classes with @Entity
annotation, which is more about RDBMS than core business logic.
I found few solutions to make it more “clean”:
- Create Repository Interface in domain and in persistence layer create RepositoryImpl that will implement domain interface and will use EntityManager with POJO:
@Repository
public class DemoRepositoryImpl implements DemoRepository {
@Autowired
private EntityManager entityManager;
@Override
public List<Object[]> findAll() {
Query q = (Query) entityManager.createNativeQuery("SELECTn" +
" demo.demo_id as demo_id,n" +
" demo.value as demo_valuen" +
" FROM Demon");
List<Object[]> results = q.getResultList();
return results;
}
}
- Create interface in domain and couple implementtion with
JpaRepositoty
:
@Repository
@RequiredArgsConstructor
public class DemoRepositoryImpl implements DemoRepository {
private final JpaDemoRepository jpaDemoRepository;
@Override
public List<Demo> findAll() {
return jpaDemoRepository.findAll().stream()
.map(entity -> new Customer(entity.getId(), entity.getName()))
.toList();
}
- Creating some dummy entity:
@Entity
@Data
public class BaseEntity {
@Id
private Long id;
}
public interface EmployeeDao extends JpaRepository<BaseEntity, Long> {
@Query(value = "select name from employee where employee_number = ?", nativeQuery = true)
Optional<Employee> get(String employeeNumber);
}
public interface Employee{
String getName();
}
However, they are ugly and deprived of certain JPA features, especially FetchType.Lazy
.
I guess it can be solved by creating 2 separate methods in repository (1 with eager fetching and 1 with lazy fetching), but I don’t think it’s good idea.
I do not want to reduce the efficiency of the code with abstract “purity,” but using Hibernate, my application is strongly tied to Hibernate and relational databases. Using Hibernate inside a Domain greatly complicates the transition to another JPA implementation, JOOQ, or even NoSQL and totally destroy clean architecture rules.
Is it worth being independent of Hibernate and relational Databases in large projects? Are there any solutions not only to build an application around the Database, but also to be able to use most of JPA privileges?