can spring-data dynamic create repository? - spring-boot

i have over 1000 repository going to create and insert data,
headerDetailLinkn00001.java
#Entity // This tells Hibernate to make a table out of this class
#Table(name="HDL_HEADER_DETAIL_LINK_00001")
public class HeaderDetailLink00001{
#Id
#Column(name="HDL_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name="DRI_ID")
private Integer driId;
#Column(name="CSD_ID")
private Integer csdId;
...getter and setter
}
HeaderDetailLink00001Repository.java
public interface HeaderDetailLink00001Repository extends JpaRepository<HeaderDetailLink00001,Long>{
List<HeaderDetailLink00001> findTopByOrderByIdDesc();
}
controller.java
#GetMapping(path = "updateHeaderDetailTable")
public #ResponseBody int updateHeaderDetailTable(#RequestParam(value = "catNum", required = true) Integer catNum)
{
List<DailyHeaderResult> listBySymcatNum = DailyHeaderResultRepository.findBycatNum(catNum);
List<HeaderDetailLink00001> chdlList = new ArrayList<HeaderDetailLink00001>();
HeaderDetailLink00001 lastRecordOflinkTableId = HeaderDetailLink00001Repository.findTopByOrderByIdDesc().get(0);
this.setPreviousIndex(lastRecordOflinkTableId.getCsdId());
logger.info("sxxxxxxxxxxxxxId==="+lastRecordOflinkTableId.getCsdId()+" "+lastRecordOflinkTableId.getDriId());
...
i am going to create HeaderDetailLink00001, HeaderDetailLink00002... HeaderDetailLink10000...etc.
is it possible make HeaderDetailLink00001 and List generate dynamically.

Related

Automatic JPA refresh ManyToOne objects with #Version feature

I'm getting an exception:
org.hibernate.TransientPropertyValueException:
object references an unsaved transient instance
- save the transient instance before flushing :
com.example.jpamapstruct.entity.Member.club ->
com.example.jpamapstruct.entity.Club
while saving the member entity:
#Transactional
public MemberDto save(MemberDto memberDto){
Member entity = memberMapper.toEntity(memberDto);
return memberMapper.toDto(repository.save(entity));
}
How to fix this case in a proper way?
Possible solution:
I can get and set a club object before saving a member but is it only one and the best approach in such scenario?
Member entity = memberMapper.toEntity(memberDto);
clubRepository.getReferencedById(memberDto.getClubId()).ifPresent(entity::setClub);
return memberMapper.toDto(repository.save(entity));
Questions:
Should I put this getReferencedById code explicity? I mean what if we have several child objects (unidirectional ManyToOne), for each we need to get data from DB.
Is there any way to handle this by JPA (Spring Data/JPA) "automatically"?
Maybe it is possible to hit DB only one time with f.e join fetch somehow for all childs (with using custom #Query or querydsl or criteria/specification)?
Next, hoow to handle collections (unidirectional manyToMany)? In my case set of events in member object. Also need to loop thru and get all objects one by one before saving member?
Where should I put such logic in a service or maybe better in a mapstuct mapper?
If so, how to use repositories in such mapper?
#Mapper(componentModel = "spring")
public interface MemberMapper extends EntityMapper<MemberDto, Member> {
#AfterMapping
default void afterMemberMapping(#MappingTarget Member m, MemberDto dto) {
var club = clubRepo.findById(m.getClub().getId())
m.setClub(club)
}
Source code:
#Entity
public class Club extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
}
public class ClubDto extends AbstractDto {
private Long id;
}
#Entity
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
// commented out as don't want to save child object as it should already exist
// #ManyToOne(cascade = CascadeType.ALL)
#ManyToOne
Club club;
#ManyToMany
#JoinTable(name = "member_events",
joinColumns = #JoinColumn(name = "member_id"),
inverseJoinColumns = #JoinColumn(name = "event_id")
)
List<Event> events = new ArrayList<>();
}
public class MemberDto {
private Long id;
private ClubDto club;
}
#MappedSuperclass
public abstract class AbstractEntity {
#Version
private Integer version;
}
public abstract class AbstractDto {
private Integer version;
}
//MemberMapper above

Why I am receiving empty array?

I am doing a project in Spring and Postgres. I am getting this empty column when I try to call a request with Postman. As you can see, it returns everything except ingredient column.
{
"recept_id": 8,
"recept_name": "conceptual",
"nation_id": 1,
"type_id": 1,
"isvegan": true,
"isvegetarian": true,
"photo": null,
"video": null,
"ingredient": [],
"level_id": 5,
"recept_view": 1,
"company_id": 4,
"ratinglvl": 5
}
However, in Postgres, this column has data ({1,2,3}). The data type of the ingredient column is an integer[] in Postgres. I inserted data to ingredient to Postgres manually.
While in Spring, I am using a simple CRUDrepository.
Entity:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "recept")
public class Recept {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long recept_id;
#Column
private String recept_name;
private long nation_id;
private long type_id;
private boolean isvegan;
private boolean isvegetarian;
private File photo;
private File video;
#ElementCollection(targetClass=Long.class)
private List<Long> ingredient;
private short level_id;
private long recept_view;
private long company_id;
private short ratinglvl;
}
Controller:
#RestController
public class ReceptController {
private final ReceptService receptService;
public ReceptController(ReceptService receptService) {
this.receptService = receptService;
}
#RequestMapping(value="/recept",method= RequestMethod.GET, headers = "Accept=application/json")
public ResponseEntity<?> getAll() {
return ResponseEntity.ok(receptService.getAll());
}
Repository:
public interface ReceptRepository extends CrudRepository<Recept, Long> {}
Service:
#Service
public class ReceptService {
private final ReceptRepository receptRepository;
private final IngredientRepository ingredientRepository;
public ReceptService(ReceptRepository receptRepository, IngredientRepository ingredientRepository) {
this.receptRepository = receptRepository;
this.ingredientRepository = ingredientRepository;
}
public List<Recept> getAll(){
return (List<Recept>)receptRepository.findAll();
}
Don't know why it doesn't return it.
#ElementCollection is meant to collect the values of a column in a related table -not to denote a PostgreSQL array type.
In order to use Postgresql arrays, you need to define a custom type. Thankfully the hibernate-types library already provides a ListArrayType out of the box. This will allow you to define your entity like:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#TypeDef(
name = "list-array"
typeClass = ListArrayType.class
)
#Table(name = "recept")
public class Recept {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long recept_id;
#Column
private String recept_name;
private long nation_id;
private long type_id;
private boolean isvegan;
private boolean isvegetarian;
private File photo;
private File video;
#ElementCollection(targetClass=Long.class)
#Type(type = "list-array)
#Column(
name = "ingredient",
columnDefinition = "integer[]"
)
private List<Long> ingredient;
private short level_id;
private long recept_view;
private long company_id;
private short ratinglvl;
}

JPARepository CPRQ modified does not save full object

I have modified the design of CPRQ a bit to help my database pattern
I have an Employee table and a Department table. Both have common properties
#Column(name="tenantIDPKFK")
private Integer tenantIdpkfk;
#Column(name="status")
private Integer status;
So I created a base class ABaseEntity like below
public class ABaseEntity {
public ABaseEntity() {
}
public ABaseEntity(int tenantIdpkfk, int status) {
this.tenantIdpkfk = tenantIdpkfk ;
this.status = status ;
}
#Column(name="tenantIDPKFK")
private Integer tenantIdpkfk;
#Column(name="status")
private Integer status;
I have extended EmployeeEntity with ABaseEntity
#Entity
#Table(name = "employee")
public class EmployeeEntity extends ABaseEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "first_name")
#NotEmpty(message = "Please provide a name")
#NotBlank
private String firstName;
My CommandHandler runs the following code
EmployeeEntity savedEmployeeEntity = this.employeeRepository.saveAndFlush(employee);
this.mediator.emit(new EmployeeCreatedEvent(savedEmployeeEntity.getId()));
Database saved the object, but only id, firstname. Does not save tenant and status columns.
I know I am missing something silly. Please help.
EDIT
Adding #MappedSuperclass to the ABaseEntity class fixed the issue.
#MappedSuperclass
public class ABaseEntity {...}
Database saved the object, but only id, firstname. Does not save
tenant and status columns.
By default JPA doesn't consider the parent class in the orm (object-relational mapping) of the current class.
You have to specify on the parent class #Inheritance with the strategy to use or use the default one.
For example :
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ABaseEntity {...}
More info here.

Hibernate Fetch #Formula annotated fields on demand

I have a entity (declared with 2 way)(some not influencing code part are ommited for readability)
Entity version 1.
#Entity
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Formula("(SELECT COUNT(w.id) FROM stock s LEFT JOIN warehouse w ON s.id=w.stock_id WHERE s.article_id = id)")
private int variants;
public int getVariants() {
return variants;
}
}
Entity version 2.
#Entity
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Transient
private int variants;
#Access(AccessType.PROPERTY)
#Formula("(SELECT COUNT(w.id) FROM stock s LEFT JOIN warehouse w ON s.id=w.stock_id WHERE s.article_id = id)")
public int getVariants() {
return variants;
}
}
respective DTO and ArticleMapper - MapStruct
#JsonIgnoreProperties(ignoreUnknown = true)
public class ArticleDTOCommon {
private Long id;
private String name;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class ArticleDTO {
private Long id;
private String name;
private int variants;
}
#Mapper(componentModel = "spring", uses = {})
public interface ArticleMapper{
ArticleDTO toDto(Article article);
ArticleDTOCommon toDtoCommon(Article article);
}
I have a #Service layer on which how i know Hibernate creates it's proxy(for defining which field is fetch or not fetch) and transactions are occurs.
#Service
#Transactional
public class ArticleService {
#Transactional(readOnly = true)
public List<ArticleDTO> findAll() {
return articleRepository.findAll()
stream().map(articleMapper::toDto).collect(Collectors.toList());
}
#Transactional(readOnly = true)
public List<ArticleDTO> findAllCommon() {
return articleRepository.findAll()
stream().map(articleMapper::toDtoCommon).collect(Collectors.toList());
}
}
It works fine with fetching Related entity but
Problem is (fetching #Formula annotated field) when I am looking executed query on log it fetchs all time variants #Formula annotated query not depending on respective DTO.
But it must be ignored on toDtoCommon - i.e. It must not fetch variants field -> because when mapping Article to ArticleDtoCommon it not uses getVariant() field of Article. I have tried multiple ways as mentioned above.
I can solve it with writing native query(for findAllCommon() method) and map respectivelly with other way... But I want to know that how we can solve it with ORM way and where is problem.
Manupulating #Access type is not helping too.
Thanks is advance.

Spring/JPA: composite Key find returns empty elements [{}]

I have build my data model using JPA and am using Hibernate's EntityManager to access the data. I am using this configuration for other classes and have had no problems.
The issue is that I created an entity with a composite primary key (the two keys are foreign keys) , adding elements works perfectly I checked it in database but I am not able to retrieve the populated row from database.
For example if I query "FROM Referentiel" to return a list of all referentiels in the table, I get this [{},{}] my list.size() has the proper number of elements (2), but the elements are null.
The entity:
#Entity
#Table(name = "Et_referentiel")
public class Referentiel implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
#JoinColumn(name = "id_projet")
private Projet projet;
#Id
#ManyToOne
#JoinColumn(name = "id_ressource")
private Ressource ressource;
#Column(name = "unite", nullable = false)
private String unite;
}
here is my controller getList method:
#PostMapping(value = "/list", consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE })
public List<Referentiel> listReferentiel(#RequestBody Long idProjet) {
List<Referentiel> referentiel = referentielService.listReferentiel(idProjet);
return referentiel;
}
and here is my dao methods:
#Autowired
private EntityManager em;
#Override
public void ajouterReferentiel(Referentiel ref) {
em.persist(ref);
em.flush();
}
#SuppressWarnings("unchecked")
#Override
public List<Referentiel> listReferentiel(Long idProjet) {
Query query = em.createQuery("Select r from Referentiel r where r.projet.idProjet=:arg1");
query.setParameter("arg1", idProjet);
em.flush();
List<Referentiel> resultList = query.getResultList();
return resultList;
}
Any help is greatly appreciated.
Try creating a class representing your composite key:
public class ReferentielId implements Serializable {
private static final long serialVersionUID = 0L;
private Long projet; // Same type than idProjet, same name than inside Referentiel
private Long ressource; // Same type than idRessource (I guess), same name than inside Referentiel
// Constructors, getters, setters...
}
And assign it to your entity having that composite key.
#Entity
#IdClass(ReferentielId.class) // <- here
#Table(name = "Et_referentiel")
public class Referentiel implements Serializable {
// ...
}
Notice that it is required to have a class representing your composite keys, even if that does not help in your problem.

Resources