A Student class has OneToOne association with an Object of type Resume and Resume class has a OneToMany association with a collection of type Master and master has a property degreeName.
What i want to achieve is:
select all the students where student.resume.masters.degreeName in (?,?,?,.....)
It should search in all the collection(Master) objects.
Below code has no compilation error but It is not giving expected result please correct me.
Student Entity:
#Entity
public class Student {
#OneToOne(fetch = FetchType.LAZY, mappedBy = "student", cascade = CascadeType.ALL)
private Resume resume;
}
Resume Entity:
#Entity
public class Resume {
#OneToMany(mappedBy="resume",cascade=CascadeType.ALL)
private List<Master> masters=new ArrayList<>();
#OneToOne(fetch=FetchType.LAZY)
#PrimaryKeyJoinColumn
private Student student;
}
Master Entity:
#Entity
public class Master {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="resume_id")
private Resume resume;
private String degreeName;
}
Dao:
Criteria studentCriteria = session.createCriteria(Student.class);
Criteria resumeCriteria = studentCriteria.createCriteria("resume");
Criteria mastersCriteria = resumeCriteria.createCriteria("masters");
List<String> degreeslist = new ArrayList<>(Arrays.asList(degrees));
//degreeList is collection of values on which the student will be searched
if (degreeslist.size() == 1) {
mastersCriteria.add(Restrictions.eq("degreeName",
degreeslist.get(0)));
} else {
mastersCriteria.add(Restrictions.in("degreeName", degreeslist));
}
Criteria mastersCriteria = getSession().createCriteria(Student.class, "student");
mastersCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
mastersCriteria.createAlias("student.resume", "resume");
mastersCriteria.createAlias("resume.masters","masters");
if (degreeslist.size() == 1) {
mastersCriteria.add(Restrictions.eq("masters.degreeName", degreeslist.get(0)));
} else {
mastersCriteria.add(Restrictions.in("masters.degreeName", degreeslist));
}
List<Student> students = mastersCriteria.list();
Related
I have two simple domain objects as follows:
USER:
#Entity
#Table(name="USER")
#IdClass(UserPK.class)
public class User implements Serializable {
//...
#Id
#Column(name = "FISCALCODE")
private String fiscalCode;
#Id
#Column(name = "USERNUMBER")
private String userNumber;
#OneToMany(mappedBy="user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Items> items;
// getters and setters
}
UserPK:
public class UserPK implements Serializable {
#Column(name = "FISCALCODE")
private String fiscalCode;
#Column(name = "USERNUMBER")
private String userNumber;
// getter and setter
}
ITEMS:
#Entity
#Table(name="ITEMS")
public class Items implements Serializable {
//...
#Id
#Column(name = "ID_ITEM")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_item_generator")
#SequenceGenerator( name = "id_item_generator", sequenceName = "ITEM_SEQ", allocationSize = 1)
private Integer id;
#ManyToOne
#JoinColumns({
#JoinColumn(name="FISCALCODE"),
#JoinColumn(name="USERNUMBER")
})
private User user;
// getters and setters
}
DB Table:
user { fiscalcode, usernumber, other columns... } // fiscalcode+usernumber = PK
items { id, fiscalcode, usernumber, other columns... } // fiscalcode,usernumber is a foreign key
CONTROLLER:
#RequestMapping(value="/user", method = RequestMethod.POST, produces = "application/json")
public Object postUser(#RequestBody(required = false) User user){
//connection etc..
session.save(user);
//...
return new ResponseEntity<>(HttpStatus.OK);
}
Why when I run the command session.save(user) Hibernate insert value null in the columns FISCALCODE and USERNUMBER of the ITEMS table?
I tried to set the ManyToOne and the JoinColumns on the getter, but the result is the same.
EDIT: i have added my method for POST operation
As it's stated in the documentation for #JoinColumns:
When the JoinColumns annotation is used, both the name and the referencedColumnName elements must be specified in each such JoinColumn annotation.
So, you should correct your mapping like below:
#ManyToOne
#JoinColumns({
#JoinColumn(name="FISCALCODE", referencedColumnName = "FISCALCODE"),
#JoinColumn(name="USERNUMBER", referencedColumnName = "USERNUMBER")
})
private User user;
Whenever a bidirectional association is formed, the application developer must make sure both sides are in-sync at all times.
So, you should have in your User entity the addItem() and removeItem() utility methods that synchronize both ends whenever a child element is added or removed like below.
#Entity
#Table(name="USER")
#IdClass(UserPK.class)
public class User implements Serializable {
//...
#OneToMany(mappedBy="user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Items> items;
// getters and setters
public void addItem(Items item) {
this.items.add(item);
item.setUser(this);
}
public void removeItem(Items item) {
this.items.remove(item);
item.setUser(null);
}
}
Example of saving:
User user = new User();
user.setFiscalCode("Code1");
user.setUserNumber("User1");
// ...
Items item1 = new Items();
Items item2 = new Items();
// ...
user.addItem(item1);
user.addItem(item2);
session.save(user);
Is there any way to update all of the references of an entity loaded into our program by hibernate all at time?
for example, I have loaded the product with id "1" in class A and change a new load of the same product with id "1" in class B. but the one in class A didn't change.
how should I fix this?
This is part of the code :
Product class :
#Entity
#Table(name = "t_product")
public class Product {
#Setter(AccessLevel.NONE)
#Id #GeneratedValue #Column(name = "ID")
private int id;
...
#ElementCollection
#OneToMany(targetEntity = SellerIntegerMap.class,
fetch = FetchType.EAGER,
cascade = CascadeType.ALL)
#JoinTable(name = "t_product_stock")
private List<SellerIntegerMap> stock;
...
}
SellerIntegerMap :
#Entity
#Table(name = "t_map")
public class SellerIntegerMap{
#Setter(AccessLevel.NONE)
#Id #GeneratedValue
private int id;
#ManyToOne
#JoinColumn(name = "SELLER")
private Seller seller;
#Column(name = "INTEGER_VALUE")
private Integer integer;
}
DBManager :
public class DBManager {
public static <T> T load(Class<T> type, Serializable serializable){
Session session = HibernateUtil.getSession();
session.beginTransaction();
T object = session.get(type,serializable);
if (object == null){
}
session.evict(object);
session.getTransaction().commit();
return object;
}
public static void save(Object object){
Session session = HibernateUtil.getSession();
session.beginTransaction();
session.saveOrUpdate(object);
session.getTransaction().commit();
}
}
and the test :
public void test(){
Product product = DBManager.load(Product.class,1);
Product productDup = DBManager.load(Product.class,1);
List<SellerIntegerMap> list = productDup.getStock();
list.get(0).setInteger(25);
DBManager.save(productDup);
}
The data is updated in SQL table but not in "product" which is a same entity like "productDup". how can I solve the problem ? is there any way to solve it in the program not loading the data every time we need them?
You need one transaction over the whole operation. That way, Hibernate will keep only a single managed instance of that entity.
I'm trying to create a one-to-one relationship between 2 entities:
Project entity
#Entity
#Table(name = "projects")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(mappedBy = "project", cascade = CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
private CrawlerConfiguration crawlerConfiguration;
// Getters and setters ...
public void setCrawlerConfiguration(CrawlerConfiguration crawlerConfiguration) {
if (crawlerConfiguration == null) {
if (this.crawlerConfiguration != null) {
this.crawlerConfiguration.setProject(null);
}
} else {
crawlerConfiguration.setProject(this);
}
this.crawlerConfiguration = crawlerConfiguration;
}
CrawlerConfiguration entity
#Entity
#Table(name = "crawler_configurations")
public class CrawlerConfiguration {
#Id
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
private Project project;
// Getters and setters ...
}
When the user creates a new project, a configuration should also be created for the project.
#Transactional
public Project createProject(Project project) {
project.setCrawlerConfiguration(new CrawlerConfiguration());
return projectRepository.save(project);
}
Unfortunately it results in the following exception:
javax.persistence.EntityExistsException: A different object with the
same identifier value was already associated with the session :
[com.github.peterbencze.serritorcloud.model.entity.CrawlerConfiguration#1]
What is the correct way to create the entities?
Try this
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
private Project project;
In your CrawlerConfiguration entity
In my code i have a oneToMany relation between customer class and item class. This means that, a customer may have one or many items.
Here is the customer code:
#Entity
#Data
public class customer {
#Id
#GeneratedValue
int id;
String name;
String lastname;
#Embedded
Address address;
#OneToMany
#Column(name="ITEM_ID")
List<item> item;
}
and it's the item class:
#Entity
#Data
public class item {
#Id
#GeneratedValue
int id;
String name;
String Serialnumber;
int price;
#ManyToOne
customer customer;
}
Then i have made some tests to try my queries in the models.
insert into item(id,name,Serialnumber,price) values(1,'bike','123',200);
insert into item(id,name,Serialnumber,price) values(2,'car','123',200);
insert into customer(id,name,lastname,Country,City,Street,No,item_id)
values(1,'Salman','Lashkarara','Iran','Tehran','Shariati','12',1);
insert into customer(id,name,lastname,Country,City,Street,No,item_id)
values(2,'Saba','Lashkarara','Iran','Tehran','Shariati','12',2);
insert into customer(id,name,lastname,Country,City,Street,No,item_id)
values(3,'Saba','Lashkarara','Iran','Tehran','Shariati','12',1);
But when i run my code, i face with the following error:
Column "ITEM_ID" not found; SQL statement:
insert into customer(id,name,lastname,Country,City,Street,No,item_id) values(1,'Salman','Lashkarara','Iran','Tehran','Shariati','12',1)
Please pay especial attention, that it is a java mvc-spring application and i create my models using the code, so there is no database to check the field item_id.
As you can see i have already added the #Column(name="ITEM_ID") to define the column.
You have to use #JoinColumn for association columns:
#OneToMany
#JoinColumn(name="ITEM_ID")
List<item> item;
some other options
#OneToMany(cascade=CascadeType.All, fetch=FetchType.EAGER)
#JoinColumn(name="ITEM_ID")
List<item> item;
in Item class
#ManyToOne(mappedBy="item")
customer customer;
you could do this i also have user class and bcr class, one user have many bcr so below code will help you
bcr.java
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_who_enter_demand", nullable = false)
public User getUserByUserWhoEnterDemand() {
return this.userByUserWhoEnterDemand;
}
public void setUserByUserWhoEnterDemand(User userByUserWhoEnterDemand) {
this.userByUserWhoEnterDemand = userByUserWhoEnterDemand;
}
user.java
#OneToMany(fetch = FetchType.LAZY, mappedBy = "userByUserWhoEnterDemand")
public Set<BudgetControlRegister> getBudgetControlRegistersForUserWhoEnterDemand() {
return this.budgetControlRegistersForUserWhoEnterDemand;
}
public void setBudgetControlRegistersForUserWhoEnterDemand(Set<BudgetControlRegister> budgetControlRegistersForUserWhoEnterDemand) {
this.budgetControlRegistersForUserWhoEnterDemand = budgetControlRegistersForUserWhoEnterDemand;
}
You can't map a table column without table:
#Entity
#Table(name = "ITEM_TABLE")
public class item {
...
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "CUSTOMER_ID_ITEM_TABLE")
private customer customer;
...
}
#Entity
#Table(name = "CUSTOMER_TABLE")
public class customer {
...
#OneToMany
#Column(name="ITEM_ID")
List<item> item;
}
I'm using Spring with Hibernate as a JPA provider and are trying to get a #OneToMany (a contact having many phonenumbers) to save the foreign key in the phone numbers table. From my form i get a Contact object that have a list of Phone(numbers) in it. The Contact get persisted properly (Hibernate fetches an PK from the specified sequence). The list of Phone(numbers) also gets persisted with a correct PK, but there's no FK to the Contacts table.
public class Contact implements Serializable {
#OneToMany(mappedBy = "contactId", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
private List<Phone> phoneList;
}
public class Phone implements Serializable {
#JoinColumn(name = "contact_id", referencedColumnName = "contact_id")
#ManyToOne
private Contact contactId;
}
#Repository("contactDao")
#Transactional(readOnly = true)
public class ContactDaoImpl implements ContactDao {
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void save(Contact c) {
em.persist(c);
em.flush();
}
}
#Controller
public class ContactController {
#RequestMapping(value = "/contact/new", method = RequestMethod.POST)
public ModelAndView newContact(Contact c) {
ModelAndView mv = new ModelAndView("contactForm");
contactDao.save(c);
mv.addObject("contact", c);
return mv;
}
}
Hopefully I got all of the relevant bits above, otherwise please let me know.
You have to manage the Java relationships yourself. For this kind of thing you need something like:
#Entity
public class Contact {
#Id
private Long id;
#OneToMany(cascade = CascadeType.PERSIST, mappedBy = "contact")
private List<Phone> phoneNumbers;
public void addPhone(PhoneNumber phone) {
if (phone != null) {
if (phoneNumbers == null) {
phoneNumbers = new ArrayList<Phone>();
}
phoneNumbers.add(phone);
phone.setContact(this);
}
}
...
}
#Entity
public class Phone {
#Id
private Long id;
#ManyToOne
private Contact contact;
...
}
In reply to Cletus' answer. I would say that it's important to have the #column annotation on the id fields, as well as all the sequence stuff. An alternative to using the mappedBy parameter of the #OneToMany annotation is to use the #JoinColumn annotation.
As a kinda aside your implementation of addPhone needs looking at. It should probably be something like.
public void addPhone(PhoneNumber phone) {
if (phone == null) {
return;
} else {
if (phoneNumbers == null) {
phoneNumbers = new ArrayList<Phone>();
}
phoneNumbers.add(phone);
phone.setContact(this);
}
}
If the Contact-Phone relationship is unidirectional, you can also replace mappedBy in #OneToMany annotation with #JoinColumn(name = "contact_id").
#Entity
public class Contact {
#Id
private Long id;
#OneToMany(cascade = CascadeType.PERSIST)
#JoinColumn(name = "contact_id")
private List<Phone> phoneNumbers;
// normal getter/setter
...
}
#Entity
public class PhoneNumber {
#Id
private Long id;
...
}
Similar in JPA #OneToMany -> Parent - Child Reference (Foreign Key)
I don't think the addPhone method is necessary, you only have to set the contact in the phone object:
phone.setContact(contact);
If you want your relationship unidirectional i.e. can navigate from Contact to Phone's only, you need to add
#JoinColumn(name = "contact_id", nullable = false)
Under your #OneToMany on your parent entity.
nullable = false IS VITAL if you want hibernate to populate the fk on the child table
Try this sample:
#Entity
public class Contact {
#Id
private Long id;
#JoinColumn(name = "contactId")
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Phone> phones;
}
#Entity
public class Phone {
#Id
private Long id;
private Long contactId;
}
In JPA this helped me
contact.getPhoneList().forEach(pl -> pl.setContact(contact));
contactRepository.save(contact);