I am new at abstract class as Entity so for training I created abstract class
@Entity
@Inheritance(strategy = TABLE_PER_CLASS)
@Getter
@Setter
@NoArgsConstructor
public abstract class ShapeEntity {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id = UUID.randomUUID().toString();
}
and classes which extand Shape:
public class SquareEntity extends ShapeEntity {
...
}
public class CircleEntity extends ShapeEntity {
...
}
every entity has repostiory like that:
public interface CircleEntityRepository extends JpaRepository<CircleEntity, String> {
}
When I want to update entity I am searching it in every repository, next (if entity was found) map parameters and finnaly have to save that entity in database. How can I easy decide which repository should be used for it? I created method save with if else which now works:
public ShapeEntity save(ShapeEntity shapeEntity) {
if (shapeEntity.getClass().getName().contains("CircleEntity")) {
return circleEntityRepository.save((CircleEntity) shapeEntity);
} else if (shapeEntity.getClass().getName().contains("SquareEntity")) {
return squareEntityRepository.save((SquareEntity) shapeEntity);
} else {
throw new EntityNotFoundException();
}
}
but it is a bit uncomfortable becouse when I will have 20 entities I will have to create 20 else if loops. Can I do any interface for this or something like that?
CodePudding user response:
If you create a ShapeEntityRepository
for the ShapeEntity class you don't need if-else blocks.
public interface ShapeEntityRepository
extends JpaRepository<ShapeEntity, String>,
JpaSpecificationExecutor<ShapeEntity> {}
ShapeEntityRepository
is useable for all classes that are extended from the ShapeEntity
class.
ShapeEntity circleEntity = new CircleEntity();
ShapeEntity squareEntity = new SquareEntity();
shapeEntityRepository.save(circleEntity);
shapeEntityRepository.save(squareEntity);
Alternatively, if there must be different repositories, you can use Spring's GenericTypeResolver to get the repository of the class.
@Component
public class RepositoryHolder {
private final List<JpaRepository> jpaRepositories;
public RepositoryHolder(List<JpaRepository> jpaRepositories) {
this.jpaRepositories = jpaRepositories;
}
public JpaRepository getRepositoryBy(Class<?> domainClass) {
Optional<JpaRepository> optionalRepository = jpaRepositories.stream()
.filter(repository -> GenericTypeResolver
.resolveTypeArguments(
repository.getClass(),
Repository.class
)[0]
.equals(domainClass))
.findFirst();
if (optionalRepository.isPresent()) {
return optionalRepository.get();
} else throw new IllegalArgumentException();
}
}
If you want to use it, your save(...)
method will be something like this:
public void save(ShapeEntity shapeEntity) {
JpaRepository repository = repositoryHolder
.getRepositoryBy(shapeEntity.getClass());
repository.save(shapeEntity);
}
Note: JPA Repository
allows to use default CRUD functions, you can add an intermediate repository bean like here and reduce these codes to that intermediate repository.