I have a database with following tables -
My State Table
with columns - id and state
My City Table
with columns - id, city and state_id
And I want to get all the cities when i request get request with a particular state id to get its cities.
State Entity Class -
#Entity
#Table(name = "states")
public class State {
#Id
private int id;
private String state;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "state_id")
private List<City> cities = new ArrayList<>();
public State() {
}
public long getId() {
return id;
}
public String getState() {
return state;
}
}
City Entity Class -
#Entity
#Table(name = "cities")
public class City {
#Id
private long id;
private String city;
private int state_id;
public City() {
}
public long getId() {
return id;
}
public String getCity() {
return city;
}
public int getState_id() {
return state_id;
}
}
How can I get this to work ?
any help is appreciated.
Related
I have Employee class and Qualification class , I added qualifications of a employee successfully. But ,When i try to update the particular employees qualification by adding one more qualification. I don't have a idea to do.Kindly suggest some view
Employee class
#Entity
#Table(name = "Tbl_Employee")
public class Employee {
private int empId;
private String empName;
private Employee_Address addressDetail;
private List<Employee_Qualification> qualifications;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="EmployeeId", updatable = false, nullable = false)
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
#Column(name="EmployeeName")
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
#OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="EmpAdd_FK")
public Employee_Address getAddressDetail() {
return addressDetail;
}
public void setAddressDetail(Employee_Address addressDetail) {
this.addressDetail = addressDetail;
}
#OneToMany(targetEntity=Employee_Qualification.class, mappedBy="employee"
,cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Employee_Qualification> getQualifications() {
return qualifications;
}
public void setQualifications(List<Employee_Qualification> qualifications) {
this.qualifications = qualifications;
}
}
Qualification class
#Entity
#Table (name="Tbl_Employee_Qualification")
public class Employee_Qualification {
private int qualificationId;
private String qualification;
private Employee employee;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="QualificationId", updatable = false, nullable = false)
public int getQualificationId() {
return qualificationId;
}
public void setQualificationId(int qualificationId) {
this.qualificationId = qualificationId;
}
#Column(name="Qualifications")
public String getQualification() {
return qualification;
}
public void setQualification(String qualification) {
this.qualification = qualification;
}
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="Emp_FK")
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
Implementation class
// Update Employee and Employee_Qualification from Employee entity class [OnetoManny and ManytoOne bidirectional]
Employee emp =(Employee) session.createQuery("from Employee where empId='10'").uniqueResult();
Employee_Qualification newQ1 = new Employee_Qualification();
newQ1.setQualification("ECE");
List<Employee_Qualification> q1 = emp.getQualifications();
q1.add(newQ1);
emp.setQualifications(q1);
session.save(q1);
session.getTransaction().commit();
When you have a bidirectional relation you need to wire up both sides. In your example you already have this:
q1.add(newQ1);
but you also need to do the reverse binding too:
newQ1.setEmployee(emp)
Just a note : You have Cascade.ALL to both relations (oneToMany and ManyToOne) between your employee and qualification. I haven' t run your code but i am pretty sure is going to create an issue.
You have to decide which entity is responsible to update the other. (i,e if you choose to save the qualifications and the changes to be propagated to employee then remove the cascade from the #oneToMany in the Employee class
I'm new to hibernate, learn doc save persistent object
followed hibernate doc this is person and phone relationship one-to-many
#Entity
#Table(name = "phone")
public class Phone {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "number")
private String number;
#ManyToOne(fetch = FetchType.LAZY)
private Person person;
//omit setter and getter
}
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
private List<Phone> phones = new ArrayList<>();
//omit getter and setter
}
I'm persistent person and add one phone the error be throw
#Test
public void say() {
Person person = new Person();
person.setUsername("aaaa");
Phone phone = new Phone();
phone.setNumber("111");
person.getPhones().add(phone);
personService.save(person);
}
this is Dao persistent
public class PersonDaoImpl implements PersonDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public void save(Person person) {
entityManager.persist(person);
}
Update service code, service just save person
#Service(value = "personService")
public class PersonServiceImpl implements PersonService {
#Autowired
private PersonDao personDao;
#Transactional
#Override
public void save(Person person) {
personDao.save(person);
}
}
error info:
23:35:47.059 [main] DEBUG org.hibernate.engine.spi.ActionQueue - Executing identity-insert immediately
23:35:47.062 [main] DEBUG org.hibernate.SQL -
insert
into
phone
(number, person_id)
values
(?, ?)
23:35:47.297 [main] DEBUG org.hibernate.engine.jdbc.spi.SqlExceptionHelper - could not execute statement [n/a]
java.sql.SQLIntegrityConstraintViolationException: Column 'person_id' cannot be null
Add the #GeneratedValue annotation to specify that the primary key for both entities will be populated outside of your code.
#Entity
#Table(name = "phone")
public class Phone {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name = "number")
private String number;
#JoinColumn("person_id")
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Person person;
//omit setter and getter
}
public class Person {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String username;
#OneToMany(mappedBy = "person")
private List<Phone> phones = new ArrayList<>();
//omit getter and setter
}
Additionally, you need to persist the Person object instead of the Phone object because there is no cascade configured from Phone to Person. If you can't do that, switch the CascadeType on Person to none and put the cascade on the Phone as shown above.
You should also add a #JoinColumn annotation on the Phone entity so hibernate is aware of the foreign key column.
You Missed something. You can try with this.
Person Entity
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String username;
#OneToMany(mappedBy = "person")
private List<Phone> phones = new ArrayList<>();
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<Phone> getPhones() {
return phones;
}
public void setPhones(List<Phone> phones) {
this.phones = phones;
}
//omit getter and setter
}
Phone Entity
#Entity
#Table(name = "phone")
public class Phone {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "number")
private String number;
#ManyToOne(cascade = CascadeType.PERSIST)
private Person person;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
//ommit setter and getter
}
Phone Dao
public interface PhoneDao {
public Phone save(Phone phone);
}
PhoneDaoImpl
#Repository
public class PhoneDaoImpl implements PhoneDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public Phone save(Phone phone) {
return entityManager.merge(phone);
}
}
PersonDaoImpl
#Repository
public class PersonDaoImpl implements PersonDao{
#PersistenceContext
private EntityManager entityManager;
#Override
public Person save(Person person) {
return entityManager.merge(person);
}
}
Test Method
#Test
#Transactional
#Commit
public void say()
{
Phone phone = new Phone();
phone.setNumber("jghjkhk");
Person person = new Person();
person.setUsername("7576");
phone.setPerson(person);
Phone pers = phoneDao.save(phone);
Assert.assertNotNull(pers);
}
Try now. It will work.
I think that you need to set the value of the person->id and then also use an getter method to pass the id to your phone object instead of passing the person object
Normally people have hibernate set the id of an entity automatically with a surrogate key.
public class Person {
#Id #GeneratedValue // should pick an appropriate strategy here
private long id;
Since you don't have that you must either add it or set it yourself.
Person p = new Person();
p.setId(1); // hopefully unique
The same goes for phone.
As you are not having any generation type on your #Id and id is the primary key which can not be null so either you have to set value of id or have #GeneratedValue annotation on your id field and set strategy either as Auto or Identity.
You can also have your own sequence generation.
Also, you need to do same for the Phone class.
I'm using Spring Boot,REST and JPA to build my application. In app, there are 2 entities with one to many relationship.
Entity 1 :
#Entity
#Table( name = "report")
#JsonIgnoreProperties(ignoreUnknown = true)
public class CustomReport {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REPORT_SEQ")
#SequenceGenerator(sequenceName = "REPORT_SEQ", allocationSize = 1, name = "REPORT_SEQ")
private Long id;
private String name;
private Long createdBy;
private Timestamp lastModifiedTimestamp;
#OneToMany(mappedBy = "customReport", cascade = CascadeType.ALL)
private Set<CustomReportActivity> customReportActivitySet;
public Set<CustomReportActivity> getCustomReportActivitySet() {
return customReportActivitySet;
}
public void setCustomReportActivitySet(Set<CustomReportActivity> customReportActivitySet) {
this.customReportActivitySet = customReportActivitySet;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public Timestamp getLastModifiedTimestamp() {
return lastModifiedTimestamp;
}
public void setLastModifiedTimestamp(Timestamp lastModifiedTimestamp) {
this.lastModifiedTimestamp = lastModifiedTimestamp;
}
}
Entity 2:
#Entity
#Table( name = "report_activity")
public class CustomReportActivity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REPORT_ACTIVITY_SEQ")
#SequenceGenerator(sequenceName = "REPORT_ACTIVITY_SEQ", allocationSize = 1, name = "REPORT_ACTIVITY_SEQ")
private Long id;
String activityName;
#ManyToOne
#JoinColumn( name="report_id" )
#JsonBackReference
private CustomReport customReport;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getActivityName() {
return activityName;
}
public void setActivityName(String activityName) {
this.activityName = activityName;
}
public CustomReport getCustomReport() {
return customReport;
}
public void setCustomReport(CustomReport customReport) {
this.customReport = customReport;
}
}
And my request JSON is as follows :
{
"name": "test report",
"createdBy" : 129,
"customReportActivitySet": [
{"activityName":"a"},
{"activityName":"b"},
{"activityName":"c"},
{"activityName":"d"},
{"activityName":"e"}
]
}
I want to save both entities in one shot. I've implemented the save functionality in following way:
#RequestMapping(value="/save", method = RequestMethod.POST)
public ResponseEntity<?> addReport(#RequestBody CustomReport customReport) {
return new ResponseEntity<>(customReportService.createCustomReport(customReport), HttpStatus.CREATED);
}
CustomReportService method:
public CustomReport createCustomReport(CustomReport customReport) {
return customReportRepository.save(customReport);
}
CustomRepository:
public interface CustomReportRepository extends CrudRepository<CustomReport, Long> {
}
But I'm getting the constraint violation exception with this:
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot
insert NULL into ("REPORT_ACTIVITY"."REPORT_ID")
Is it possible to save both entities in one save operation?
Please help!
You would have to add a small piece of code which would populate each CustomReportActivity within the CustomReport instance. Only then the persistence provide can successfully perform the cascade save operation:
public CustomReport createCustomReport(CustomReport customReport) {
customReport.getCustomReportActivitySet.forEach((activity) -> {
activity.setCustomReport(customReport);
});
return customReportRepository.save(customReport);
}
The bottom line is that the dependencies have to be set on both sides of the relationship.
Try this sample, in my case it worked as expected, child entities are saved automatically in a single save operation with creating relations to the parent entity:
#Entity
public class Parent {
#Id
private Long id;
#JoinColumn(name = "parentId")
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Child> children;
}
#Entity
public class Child {
#Id
private Long id;
private Long parentId;
}
i am trying to create a bidirectional one to many relationship.
#Entity
#XmlRootElement
#NamedQueries({
#NamedQuery(name = Company.FIND_ALL, query = "select c from Company
})
public class Company {
public static final String FIND_ALL = "Company.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String email;
private String name;
private String phoneNumber;
#OneToMany(mappedBy = "company")
private List<Place> places;
private long millisSince1970;
private boolean deleted;
public Company() {
}
#PrePersist
public void addMillisPrePersist() {
millisSince1970 = Instant.now().getEpochSecond();
deleted = false;
}
#PreUpdate
public void addMillisPreUpdate() {
millisSince1970 = Instant.now().getEpochSecond();
}
}
Place class:
#Entity
#XmlRootElement
#NamedQueries({
#NamedQuery(name = Place.FIND_ALL, query = "select p from Place p")
})
public class Place {
public static final String FIND_ALL = "Place.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private Type type;
private String email;
private String name;
private String city;
private String address;
private String phoneNumber;
private String latitude;
private String longitude;
private String workingHours;
#ManyToOne
#JoinColumn(name = "company_id", referencedColumnName = "id", nullable = false)
private Company company;
#OneToMany(mappedBy = "place")
private List<SpecialOffer> specialOffers;
#OneToMany(mappedBy = "place")
private List<Event> events;
private long millisSince1970;
private boolean deleted;
public Place() {
}
#PrePersist
public void addMillisPrePersist() {
millisSince1970 = Instant.now().getEpochSecond();
deleted = false;
}
#PreUpdate
public void addMillisPreUpdate() {
millisSince1970 = Instant.now().getEpochSecond();
}
}
And here is simple resource:
#GET
#Path("{companyId}")
#Produces({MediaType.APPLICATION_JSON})
public Company getCompany(#PathParam("companyId") int id) {
return entityManager.find(Company.class, id);
}
In my database i have Company and Place tables, in the Place table i have a foreign key column named company_id, so when i try to get some Company which has some corresponding Place glassfish returns http status 500 internal server error without any exception, and server logs are empty, thus i can not debug or understand the cause of this problem. If i try to get the company which doesn't have any places it returns it without any problem. So what am i doing wrong?
P.S. i think my question is similar to this one Glassfish: HTTP 500 Internal Server Error without any exception which unfortunately doesn't have any responses
I have two classes Task and TaskComponents. TaskComponents contains a task mapped by a Task_ID. I am trying to select a task joined to the TaskComponents table. I have tried many different SQL statements but all of them come back with QuerySyntaxException Path Expected to join.
Task POJO
#Entity
#Table(name = "task")
public class Task implements Serializable {
#Id
#Column(name = "ID")
private int Id;
#Column(name = "Name")
private String name;
#Column(name = "Description")
private String description;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Site_ID")
private Site site;
public int getId() {
return Id;
}
public void setId(int Id) {
this.Id = Id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Site getSite() {
return site;
}
public void setSite(Site site) {
this.site = site;
}
}
TaskComponents POJO
#Entity
#Table(name = "taskcomponents")
public class TaskComponents implements Serializable {
#Id
#Column(name = "ID")
private int Id;
#Column(name = "VersionName")
private String versionName;
#Column(name = "Live", nullable = false)
#Type(type = "org.hibernate.type.NumericBooleanType")
private boolean live;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Task_ID")
private Task task;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Group_ID")
private GroupDB group;
public int getId() {
return Id;
}
public void setId(int Id) {
this.Id = Id;
}
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
public Task getTask() {
return task;
}
public void setTask(Task task) {
this.task = task;
}
public GroupDB getGroup() {
return group;
}
public void setGroup(GroupDB group) {
this.group = group;
}
}
And my attempted queries.
Query query = session.createQuery("SELECT t FROM Task t INNER JOIN TaskComponents tc ON t.Id=tc.task.Id");
Query query = session.createQuery("SELECT t FROM Task t INNER JOIN TaskComponents tc ON t=tc.task");
You shouldn't use explicitely ON to define the join, Hibernate will infer it from the mapping, just write you query as
SELECT tc.task FROM TaskComponents tc INNER JOIN tc.task
this is what is referred to behind your error message Path expected for join the query expects a property defined path from one entity to another