Student.java
#Entity
#Table(name = "Student")
#Data
#NoArgsConstructor
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "studentId", cascade = CascadeType.ALL)
private List<Subject> subjectList = new ArrayList<>();
public void addSubject(Subject subject) {
subjectList.add(subject);
subject.setStudentId(this);
}
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
}
Subject.java
#Entity
#Table(name = "Subject")
#Data
#NoArgsConstructor
public class Subject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="studentId", nullable = false)
private Student studentId;
#Column(name = "subjectName")
private String subjectName;
#Column(name = "subjectCode")
private int subjectCode;
}
SubjectRepository.java
#Repository
public interface SubjectRepository extends JpaRepository<Subject, Long> {
}
As shown in the code structure above, I have 2 entities (Student, Subject) and a repository class (SubjectRepository). When i try to save into the Subject table, somehow the student name "Thomas" from the Student table gets updated as well in the database. I would like to only insert into Subject table without having any values from the Student table getting updated. Need some help on this. Thanks!
public static void main(String[] args) {
#Autowired protected SubjectRepository subjectRepository;
Student student = new Student();
student.setFirstName("Thomas");
Subject subject = new Subject();
subject.setSubjectName("Chemistry");
subject.setSubjectCode(12345);
student.addSubject(subject)
subjectRepository.save(subject)
}
I would like to only insert into Subject table without having any values from the Student table getting updated
You can achieve this with following code :
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="studentId", nullable = false, updatable = false)
private Student studentId;
When using Spring JPA I would suggest using the JpaRepository API. You just need to pass in your entity, and it should save as desired.
Ex:
subjectRepository.save(subject);
You have try this
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name="studentId", nullable = false, updatable = false)
private Student studentId;
#MaxExplode You have to use cascade = CascadeType.REFRESH then other details will not update. but if you are try to set updateStudent.setfirstNamr(student.getFirstName()); and then save parent object then i will update. otherwise it will not update.
Related
I have a spring boot application with two entities in a relationship. MeetingSetting and MeetingTime meetingSetting can have unlimited meetingTimes. So far the databases are generating without problem, but When I try to save my Entity they are saved but different from each other, they are saved independently. Meaning MeetingName which is a foreign key inside MeetingTime is not saved but seen as null (I debugged and tried finding out why but could not find anything) THe other values are saved-
could someone point me out what my error is?
this is the json I am sending:
{
"meetingName":"TEst",
"meetingPw":"",
"meetingTime":[
{
"date":"2021-05-31",
"startTime":"15:30",
"endTime":"16:30"
},
{
"date":"2021-06-21",
"startTime":"15:30",
"endTime":"17:30"
},
{
"date":"2021-06-21",
"startTime":"11:01",
"endTime":"11:01"
}
]
}
MeetingSettings:
#Entity
#Table(name = "meeting_settings")
#Data
public class MeetingsSetting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name", unique = true)
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meeting_Name", cascade = CascadeType.ALL)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
MeetingTime:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#ManyToOne
#JoinColumn(name = "meeting_name" ,insertable = false, updatable = false , referencedColumnName = "meeting_name")
private MeetingsSetting meeting_Name;
}
this is how I try to save the entity:
#RestController
#RequestMapping("/api/meetingSetting")
public class MeetingSettingController {
#Autowired
MeetingSettingService meetingSettingService;
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingSettingService.saveMeeting(meetingsSetting);
}
}
My service calls the save method of an jpaRepository.
In a bi-directional One to Many, you have to synchronize both sides of the association.
You can simply iterate over all MeetingTime objects and set the corresponding MeetingSetting to it.
Your MeetingSettingService's saveMeeting method could do this:
public void saveMeeting(MeetingsSetting meetingsSetting) {
// ...
// here you're synchronizing both sides of the association
meetingsSetting.getMeetingTime()
.forEach(mt -> mt.setMeetingSetting(meetingSetting));
// ...
repository.save(meetingSetting);
}
Solution to my question, I am not sure if this is a good or correct way of solving this maybe someone can advice me a better solution:
#Entity
#Table(name = "meeting_times")
#Data
public class MeetingTime implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "meeting_name")
private String meeting_name;
THIS IS THE PART WHICH IS CALLED FROM THE METHOD INSIDE MEETINGSCONTROLLER
#Column(name = "end_time")
private String endTime;
#ManyToOne
#JoinColumn(name = "meeting_name" ,insertable = false, updatable = false, referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
}
MeetingsTime Entity:
#RestController
#RequestMapping("/api/meetingSetting")
public class MeetingSettingController {
#Autowired
MeetingSettingService meetingSettingService;
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingsSetting.getMeetingTime()
.forEach(mt -> mt.setMeeting_name(meetingsSetting.getMeetingName()));
// ...
meetingSettingService.saveMeeting(meetingsSetting);
}
}
I want to store recipes and ingredients in db. I came up with these entities:
#Entity
public class Recipe {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String notes;
#OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
private List<IngredientQuantity> ingredientQuantities = new ArrayList<>();
}
#Entity
public class Ingredient {
#Id
private String name;
#OneToMany(mappedBy = "ingredient", cascade = CascadeType.ALL)
private List<IngredientQuantity> ingredientQuantities = new ArrayList<>();
}
#Entity
public class IngredientQuantity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "fk_recipe")
private Recipe recipe;
#ManyToOne
#JoinColumn(name = "fk_ingredient")
private Ingredient ingredient;
private double quantity;
}
Now when I want to create a new recipe, I would have to check every ingredient if they already exist in db or not. Is this approach any good? And if it is fine, do I make a one call to db to fetch all ingredients using "WHERE (...) IN ()" clause or hit db with multiple single queries?
Let's say I have those two entities, Person & Insurance. One Person can have multiple insurances, and the insurance uniqueness is maintained by a composite key combination of (insurance type, policy number, and person id). The below code represent the the scenario...
parent class
#Entity
#Setter
#Getter
#RequiredArgsConstructor
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = "GenerationType.IDENTITY")
#Column(name "person_id")
private Long personId;
#Column(name = "fst_nm")
private String fstName;
#Column(name = "lst_nm")
private String lstNm;
// ..Other columns & relationships
#OneToMany(mappedBy = "person")
private List<Insurance> insurances;
public void addInsurance(Insurance toAdd) {
getInsurances().add(toAdd);
toAdd.setPerson(this);
}
}
child class
#Entity
#Setter
#Getter
#RequiredArgsConstructor
public class Insurance implements Serializable {
#EmbeddedId
private insurancePK id;
//other data
#ManyToOne
#MapsId("personId")
private Person person;
}
composite PK class
#Setter
#Getter
#Embeddable
public class InsurancePK implements Serializable {
#Column(name = "person_id", insertable = false, updatable = false)
private Long personId;
#Column(name = "insurance_type")
private String insuranceType;
#Column(name = "pol_num")
private String polNum;
}
now, my data mapper looks something like that...
Person newPerson = new Person();
newPerson.setInsurances(new ArrayList<>());
// fill out Person Model data
// incoming insurance data
while (incomingData.hasNext()) {
Insurance insuranceData = new Insurance();
InsurancePK pk = new InsurancePK();
// set other insurance data
pk.setInsuranceType("Dental");
pk.setPolNum("123Abc00");
insuranceData.setId(pk);
person.addInsurance(insuranceData);
}
Problem is my person_id inside the composite key is always getting a null value, not sure why (shouldn't the #MapsId takes care of that value)?
I need to fetch that value dynamically, most of the JPA composite key solutions only are setting all the value manually, but that's not my scenario.
return object from saveAndflush()
{
person: {
person_id: 55,
fst_nm: blah,
lst_nm: blah,
insurances: [
{
insurance_pk: {
person_id: null,
insurance_type: "Dental",
pol_num: "123Abc00"
}
//other insurance data
}
]
}
}
any suggestions on what am I missing? Thank you in advance!
Remove the #Column(name = "person_id", insertable = false, updatable = false) annotation from the InsurancePK.personId.
Add the following annotation:
#JoinColumn(name = "name = "person_id"")
to the Insurance.person.
As mentioned in the comments, adding a cascade to my entity column started me on the right track.
just in case, that's the model that worked for me after couple of tries
Parent class
#Entity
#Setter
#Getter
#RequiredArgsConstructor
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = "GenerationType.IDENTITY")
#Column(name "person_id")
private Long personId;
#Column(name = "fst_nm")
private String fstName;
#Column(name = "lst_nm")
private String lstNm;
// ..Other columns & relationships
// cascade added <-- thanks to SternK
#OneToMany(mappedBy = "person", casecade = CascadeType.ALL, orphanRemoval = true)
private List<Insurance> insurances;
public void addInsurance(Insurance toAdd) {
getInsurances().add(toAdd);
toAdd.setPerson(this);
}
}
Child class
#Entity
#Setter
#Getter
#RequiredArgsConstructor
public class Insurance implements Serializable {
#EmbeddedId
private insurancePK id;
//other data
#ManyToOne
#MapsId("personId")
// annotation added here instead of PK class <-- fix
#JoinColumn(name="person_id", nullable = false, insertable = false, updatable = false)
private Person person;
}
PK class
#Setter
#Getter
#Embeddable
public class InsurancePK implements Serializable {
//annotation removed <-- fix thanks to SternK
private Long personId;
#Column(name = "insurance_type")
private String insuranceType;
#Column(name = "pol_num")
private String polNum;
}
I have 2 classes - Person and Team.
One person can be in only one team, but one team can have many people (person objects). The problem is that both Person and Team need the other class objects to create themselves.
Classes:
#Entity
#Table(name = "Team")
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private int id;
#Column(name = "teamName", nullable = false)
private String teamName;
#OneToMany(mappedBy = "myTeam", fetch = FetchType.LAZY)
private Set <Person> setOfMembers = new HashSet<Person>();
public Team(int id, String teamName, Set <Person> setOfMembers) {
//usual code (don't want to waste so much space)
}
... other irrelevant fields ...
}
#Entity
#Table(name = "Person")
public class Person{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", nullable = false)
private int id;
#Column(name = "teamID", nullable = false)
private int teamID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "teamID", referencedColumnName = "id")
private Team myTeam;
public Person(int id, int teamID, Team myTeam) {
//usual code
}
... other irrelevant fields ...
}
Now in the main file, i'm trying to create a new object:
Team t1 = new Team(1,"Nights Watch", <and here i need Person Object, so i
do something as follows:> new Person(1,1, <and here i need Team object>));
so it goes recurrent, without end.
I want to add some records to the database, but i don't know how.
Actually I need there the Set of Person Objects, but still, i don't know how
Why do you need all your teammates during the initialization of the Team class ?
Just do a constructor without the Person argument, and then do a method like:
public void addTeamMember(Person person) {
setOfMembers.add(person);
}
Then, you can create the Team, create the Person and finally add the Person to the Team.
I have student, test and student_test tables with many-to-many relationship.
Test:
#Entity
#Table(name = "TEST")
public class Test
{
#Id
#Column(name = "TEST_ID")
#GeneratedValue
private Long testId;
#Column(name = "SUBJECT")
private String subject;
#Column(name = "MAX_MARKS")
private String maxMarks;
#Column(name = "MARKS_OBTAINED")
private String marksObtained;
#Column(name = "RESULT")
private String result;
#ManyToMany(fetch = FetchType.LAZY,
mappedBy = "test",
cascade= {CascadeType.PERSIST})
private Set<Student> student = new HashSet<Student>();
}
Student:
#Entity
#Table(name = "STUDENT")
public class Student
{
#Id
#Column(name = "STUDENT_ID")
#GeneratedValue
private Long studentId;
#Column(name = "FIRSTNAME")
private String firstname;
#Column(name = "LASTNAME")
private String lastname;
#Column(name = "EMAIL")
private String email;
#Column(name = "PHONE")
private String phone;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "STUDENT_TEST",
joinColumns = { #JoinColumn(name = "STUDENT_ID", updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "TEST_ID", updatable = false) })
private Set<Test> test = new HashSet<Test>();
}
I have created test record separately.
Now I wanted to insert a Student with relationship record.
The following code is trying to
update student record
update test record
insert a record in relationship table (student_test).
Test test1 = new Test();
test1.setTestId(Long.valueOf("3"));
student1.getTest().add(test1);
student1.setStudentId(Long.valueOf("1"));
try
{
session.saveOrUpdate(student1);
}
catch (HibernateException e)
{
e.printStackTrace();
}
session.getTransaction().commit();
session.close();`
My question is, I need to insert a record into Student and relationship table(student_test) only and it should not update record in test table.
I guess, you forgot to begin transaction. Add following line before saveUpdate
session.getTransaction().begin();
Every thing seems ok except your transaction management.. But I did not see the transaction open in your posted code but you have only transaction commit.. can you make the change and do test again ?
Cheers!