Entity Fields Mapping from one entity to other - spring-boot

I have three tables:
survey_question_answer_mapping(id, survey_question_id, survey_answer_id, answer_order)
survey_question(id, text)
survey_answer(id, text)
And respective Entity and DTO:
SurveyQuestionAnswerMappingEntity.java
#OneToOne
#JoinColumn(name = "survey_question_id")
private SurveyQuestionEntity surveyQuestion;
#OneToOne
#JoinColumn(name = "survey_answer_id")
private SurveyAnswerEntity surveyAnswer;
private Integer answerOrder;
SurveyQuestionEntity.java
private String text;
SurveyAnswerEntity.java
private String text;
#Transient
private Integer answerOrder;//Not present in actual table... temp variable to be mapped from mapping entity
#ManyToMany(mappedBy = "surveyAnswers")
#ToString.Exclude
private Set<SurveyQuestionEntity> surveyQuestions = new HashSet<>();
Now Question is I want to map SurveyQuestionAnswerMappingEntity.java -> answerOrder to SurveyAnswerEntity -> answerOrder(i.e. transient).
While fetching all survey I want repository call to automatically map required fields answerOrder from mapping to answer entity.
List<SurveyQuestionEntity> surveyQuestionEntities = surveyQuestionEntityRepository.findAll();
So, Here each of surveyQuestionEntities -> Set surveyAnswers; and each of surveyAnswers -> answerOrder which got map automatically from SurveyQuestionAnswerMappingEntity -> answerOrder.
Is this possible? If Yes then How? With example?

Related

Inject data in json entity with Spring Data REST

I have JPA entity for department:
public class Department {
#Id
#Column(unique = true, nullable = false)
private long id;
#Basic
#Column
#Nationalized
private String name;
#Basic
#Column(length = 400)
#Nationalized
private String branch;
...
}
And REST repository
#RepositoryRestResource(collectionResourceRel = "departments", path = "departments")
public interface DepartmentRestRepository extends PagingAndSortingRepository<Department, Long> {
...
}
Entity's branch field is IDs of entity parent departments separated by space, e.g. 1 2 3.
When I query specific department via /api/departments/ID is it possible to attach to it field like parents with all parent entities queried?
I tryed to add getParents method to entity, but it obviously gave me unneeded parents queries with all entities recursively.
Update 2019.01.17:
As a workaround I splitted Department entity into Department and DepartmentWithParents. I added Department getParents() method to DepartmentWithParents entity and exposed REST API method that returns DepartmentWithParents.
Is there better way?
As a workaround I splitted Department entity into Department and DepartmentWithParents. I added Department getParents() method to DepartmentWithParents entity and exposed REST API method that returns DepartmentWithParents.

Bulk data to find exists or not : Spring Data JPA

I get an Post request that would give me a List<PersonApi> Objects
class PersonApi {
private String name;
private String age;
private String pincode ;
}
And I have an Entity Object named Person
#Entity
#Table(name = "person_master")
public class Person{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Column(name = "name")
String name;
#Column(name = "age")
String age;
#Column(name = "pincode ")
String pincode ;
}
My record from Post request would look something like this (pseudocode representation of the data below)
[
"Arun","33","09876gh"
"James","34","8765468"
]
I need to do a bulk-validation using Spring JPA.. Give the List<PersonApi> and get a True or False based on the condition that all the entries in the PersonApi objects list should be there in the database.
How to do this ?
The selected answer is not a right one. (not always right)
You are selecting the whole database to check for existence. Unless your use case is very special, i.e. table is very small, this will kill the performance.
The proper way may start from issuing repository.existsById(id) for each Person, if you never delete the persons, you can even apply some caching on top of it.
exists
Pseudo Code:
List<PersonApi> personsApiList = ...; //from request
List<Person> result = personRepository.findAll();
in your service class you can access your repository to fetch all database entities and check if your list of personapi's is completeley available.
boolean allEntriesExist = result.stream().allMatch(person -> personsApiList.contains(createPersonApiFromPerson(person)));
public PersonApi createPersonApiFromPerson(Person person){
return new PersonApi(person.getName(), person.getAge(), person.getPincode());
}

one-way one-to-many throws Hibernate Cannot add or update a child row: a foreign key constraint fails

I have an application that teaches the user how to play various card games. The data model that gets persisted consists of a TrainingSession with a uni-directional one-to-many relationship with the Hands.
[EDIT] To clarify, a Hand has no existence outside the context of a TrainingSession (i.e they are created/destroyed when the TrainingSession is). Following the principals of Data Driven Design, the TrainingSession is treated as an aggregate root and therefore a single spring-data CrudRepository is used (i.e., no repository is created for Hand)
When I try to save a TrainingSession using a CrudRepository, I get: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (blackjack.hand, CONSTRAINT FKrpuxac6b80xc7rc98vt1euc3n FOREIGN KEY (id) REFERENCES training_session (tsid))
My problem is the 'save(trainingSession)' operation via the CrudRepository instance. What I don't understand is why the error message states that FOREIGN KEY (id) REFERENCES training_session (tsid)). That seems to be the cause of the problem but I cant figure out why this is the case or how to fix it. The relationship is uni-directional and nothing in the Hand class refers to the TrainingSession.
The code, minus all the getters and setters, is:
#Entity
public class TrainingSession {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer tsid;
private String strategy;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="id")
private List<Hand> hands;
private int userId;
protected TrainingSession() {
}
public TrainingSession(int userId, Strategy strategy, List<Hand> hands) {
this.strategy = strategy.getClass().getSimpleName();
this.hands = hands;
this.userId = userId;
}
while Hand is
#Entity // This tells Hibernate to make a table out of this class
public class Hand {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int p1;
private String p1s;
private int p2;
private String p2s;
private int d1;
private String d1s;
private int trials;
private int score;
public Hand() {
}
You need to save your TrainingSession and Hand objects first before saving the adding the hand objects to TrainingSession.
TrainingSession ts1 = new TrainingSession();
trainingSessionManager.save(ts1);
Hand hand1 = new Hand();
handManager.save(hand1);
Hand hand2 = new Hand();
handManager.save(hand2);
ts1.gethands().add(hand1);
ts1.gethands().add(hand2)
trainingSessionManager.save(ts1);
If you check your database you will find 3 tables TrainingSession, Hand and TrainingSession_Hand, The TrainingSession_Hand table references to both TrainingSession and Hand both. Therefore you need to save TrainingSession and hand before saving the relationship.
Found the problem. I was assuming that when spring-data set up the DB tables, it was able to figure out and set up the uni-directional 1-to-many relationship. Apparently that isn't the case. When I configure the relationship as bi-directional everything seems to work.
To fix things I:
removed from TrainingSession the #joincolumn annotation for hands
in Hands I added a TrainingSession field with a #ManyToOne annotation:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "tsid", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private TrainingSession tsession;
I also added in the Hand class the getter/setter for tsession
I can now do a save of the entire aggregate construct using only a TrainingSessionRepository.

How can I include or exclude a record according to a boolean parameter using Spring Data JPA?

I am not so into Spring Data JPA and I have the following doubt about how to implement a simple query.
I have this AccomodationMedia entity class mapping the accomodation_media on my database:
#Entity
#Table(name = "accomodation_media")
public class AccomodationMedia {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "id_accomodation")
private Long idAccomodation;
#Column(name = "is_master")
private boolean isMaster;
#Lob
#Column(name = "media")
private byte[] media;
private String description;
private Date time_stamp;
public AccomodationMedia() {
}
...............................................................
...............................................................
...............................................................
// GETTER AND SETTER METHODS
...............................................................
...............................................................
...............................................................
}
The instance of this class represents the photo associated to an accomodation (an hotel)
So as you can see in the prvious code snippet I have this field :
#Column(name = "id_accomodation")
private Long idAccomodation;
that contains the id of an accomodation (the id of an hotel on my database).
I also have this boolean field that specify if an image is the master image or not:
#Column(name = "is_master")
private boolean isMaster;
So, at this time, in my repository class I have this method that should return all the images associated to a specific hotel:
#Repository
public interface AccomodationMediaDAO extends JpaRepository<AccomodationMedia, Long> {
List<AccomodationMedia> findByIdAccomodation(Long accomodationId);
}
I want to modify this method passing also the boolean parameter that specify if have to be returned also the master image or only the images that are not master.
So I tryied doing in this way:
List<AccomodationMedia> findByIdAccomodationAndIsMaster(Long accomodationId, boolean isMaster);
but this is not correct because setting to true the isMaster parameter it will return only the master image (because it is first selecting all the Accomodation having a specific accomodation ID and then the one that have the isMaster field setted as true).
So, how can I correctly create this query that use the isMaster boolean parameter to include or exclude the AccomodationMedia instance that represent my master image?
I know that I can use also native SQL or HQL to do it but I prefer do it using the "query creation from method names"
I don't have how to test this, but essentially your final query should be:
id_accomodation = ?1 AND (is_master = ?2 OR is_master = false)
So I would try the following method signature:
findByIdAccomodationAndIsMasterOrIsMasterFalse(Long accomodationId, boolean isMaster);
I would go with two methods one for isMaster true, while second for false value like this:
List<AccomodationMedia> findByIdAccomodationAndIsMasterFalse(Long accomodationId);
List<AccomodationMedia> findByIdAccomodationAndIsMasterTrue(Long accomodationId);
Change your acommodation id as accomodationId instead of idAccomodation. When you write findByIdAccomodationAndIsMaster spring confusing findByIdAccomodationAndIsMaster
Try this this convention
#Column(name = "accomodation_id")
private Long accomodationId;

Hibernate: need update parent entity without pulling all its child-cascade

I faced the problem when I need to partially udate data in BD.
What I have:
I have three linked entities:
Profile --(1-m)--> Person --(1-1)--> Address
Where Person -> Address is lazy relationship. It was achieved via optional=false option (that allow hibernate to use proxy).
What the problem:
I need to update Profile in such way, that I needn't pull all Addresses that linked with this profile.
When I update Profile (don't work):
profile.setPersons(persons);
session.saveOrUpdate(profile);
throws: org.springframework.dao.DataIntegrityViolationException: not null property references a null or transient value
It happens because Person->Address relationship has optional=false option
I need to do:
//for each person
Address address = requestAddressFromDB();
person.setAddress(address);
persons.add(person)
//and only then
profile.setPersons(persons);
session.saveOrUpdate(profile);
profile.setPerson(person)
But I don't want to pull all address each time I update Profile name.
What is the question:
How can I avoid obligatory Person->(not null)Address constraint to save my profile without pulling all addresses?
ADDITION:
#Entity
public class Person{
#Id
#SequenceGenerator(name = "person_sequence", sequenceName = "sq_person")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "person_sequence")
#Column(name = "id")
private long personID;
#OneToOne(mappedBy="person", cascade=CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
private Address address;
//.. getters, setters
}
#Entity
public class Address {
#Id
#Column(name="id", unique=true, nullable=false)
#GeneratedValue(generator="gen")
#GenericGenerator(name="gen", strategy="foreign", parameters=#Parameter(name="property", value="person"))
private long personID;
#PrimaryKeyJoinColumn
#OneToOne
private FileInfo person;
}
Modify the cascade element on the #OneToOne annotation so that the PERSIST operation is not cascaded. This may require you to manually persist updates to Address in certain areas of your code. If the cascade is not really used however no change is needed.
#OneToOne(mappedBy="person", cascade={CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH}, optional = false, fetch = FetchType.LAZY)
private Adress address; //Do you know that Address is missing a 'd'?

Resources