I am trying to persist one object which has inside list.
I had to annotate the entity Item with #JsonManagedReference
and ItemProperty with #JsonBackReference, to avoid infinite loop - break the cycle.
And for getting items with item properties is fine. The problem is now when I try to persist the new Item with list of item properties, then only the Item is persisted, without any ItemProperties. Any one know why's that? Has the #JsonBackReference/ManagedReference annotations something with it?
CODE:
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.util.List;
import java.util.Objects;
#Entity
#Table(name = "item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Enumerated(EnumType.STRING)
#Column(name = "type")
private ItemType itemType;
#OneToMany(mappedBy = "item")
// #JsonManagedReference is the forward part of reference which gets serialized normally.
#JsonManagedReference
private List<ItemProperty> itemProperties;
public Item() {
}
public Item(ItemType itemType, List<ItemProperty> itemProperties) {
this.itemType = itemType;
this.itemProperties = itemProperties;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public ItemType getItemType() {
return itemType;
}
public void setItemType(ItemType itemType) {
this.itemType = itemType;
}
public List<ItemProperty> getItemProperties() {
return itemProperties;
}
public void setItemProperties(List<ItemProperty> itemProperties) {
this.itemProperties = itemProperties;
}
#Override
public String toString() {
return "Item{" +
"id=" + id +
", itemType=" + itemType +
", itemProperties=" + itemProperties +
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Item item = (Item) o;
return id == item.id &&
itemType == item.itemType &&
Objects.equals(itemProperties, item.itemProperties);
}
#Override
public int hashCode() {
return Objects.hash(id, itemType, itemProperties);
}
}
ITEM PROPERTY:
import com.fasterxml.jackson.annotation.JsonBackReference;
import javax.persistence.*;
import java.util.Objects;
#Entity
#Table(name = "item_properties")
public class ItemProperty {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "item_id")
#JsonBackReference
private Item item;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "item_property_definition_id")
private ItemPropertyDefinition itemPropertyDefinition;
#Column(name = "value")
private String value;
public ItemProperty(){}
public ItemProperty(Item item, ItemPropertyDefinition itemPropertyDefinition, String value) {
this.item = item;
this.itemPropertyDefinition = itemPropertyDefinition;
this.value = value;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public ItemPropertyDefinition getItemPropertyDefinition() {
return itemPropertyDefinition;
}
public void setItemPropertyDefinition(ItemPropertyDefinition itemPropertyDefinition) {
this.itemPropertyDefinition = itemPropertyDefinition;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return "ItemProperty{" +
"id=" + id +
", item=" + item +
", itemPropertyDefinition=" + itemPropertyDefinition +
", value='" + value + '\'' +
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ItemProperty that = (ItemProperty) o;
return id == that.id &&
Objects.equals(item, that.item) &&
Objects.equals(itemPropertyDefinition, that.itemPropertyDefinition) &&
Objects.equals(value, that.value);
}
#Override
public int hashCode() {
return Objects.hash(id, item, itemPropertyDefinition, value);
}
}
IN REST CONTROLLER:
#PostMapping("/items")
Item addItem(#RequestBody Item item) {
item.setId(0);
return this.itemService.addItem(item);
}
Thanks in advance for hints.
Have a nice day and happy coding!
You haven´t declared the cascade flag in the #OneToMany. By default no operation on an item entity is cascaded to the ItemProperty list. So take a look into the CascadeType enum and set the operations you want to be cascaded to the itemsproperty list. For more information on CascadeTypes look here.
Example:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "item", orphanRemoval = true)
// #JsonManagedReference is the forward part of reference which gets serialized normally.
#JsonManagedReference
private List<ItemProperty> itemProperties;
If you wonder what´s the orphanRemoval good for take a look at this question.
The C.Weber answer was right but also #Transactional annotation was missing.
Related
I can’t set the discipline values for my semester, when I work out the controller, I get all the data I need, but I can’t connect them, can anyone tell me with an experienced eye what is the reason? I am getting this kind of error:
Request processing failed; nested exception is
org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private int com.kushnirmark.spring.project.entity.Discipline.id] by reflection for persistent property [com.kushnirmark.spring.project.entity.Discipline#id] : Higher mathematics
Here is my entity Semestr:
package com.kushnirmark.spring.project.entity;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
#Entity
#Table(name = "semestr")
public class Semestr {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "duration")
private String duration;
#Column(name = "status")
private boolean status = true;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "semestr_discipline",
joinColumns = #JoinColumn(name = "id_semestr"),
inverseJoinColumns = #JoinColumn(name = "id_discipline")
)
private List<Discipline> disciplineList;
public void addDisciplineToSemester(Discipline discipline) {
if (disciplineList == null) {
disciplineList = new ArrayList<>();
}
disciplineList.add(discipline);
}
public Semestr() {
}
public Semestr(int id, String name, String duration, boolean status) {
this.id = id;
this.name = name;
this.duration = duration;
this.status = status;
}
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 getDuration() {
return duration;
}
public void setDuration(String duration) {
this.duration = duration;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public List<Discipline> getDisciplineList() {
return disciplineList;
}
public void setDisciplineList(List<Discipline> disciplineList) {
this.disciplineList = disciplineList;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Semestr semestr = (Semestr) o;
if (id != semestr.id) return false;
if (status != semestr.status) return false;
if (name != null ? !name.equals(semestr.name) : semestr.name != null) return false;
return duration != null ? duration.equals(semestr.duration) : semestr.duration == null;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (duration != null ? duration.hashCode() : 0);
result = 31 * result + (status ? 1 : 0);
return result;
}
#Override
public String toString() {
return "Semestr{" +
"id=" + id +
", name='" + name + '\'' +
", duration='" + duration + '\'' +
", status=" + status +
'}';
}
}
Controller :
#RequestMapping("/saveNewSemester")
public String saveNewSemester(#ModelAttribute("semestr") Semestr semestr,
#RequestParam(name = "AllDiscipline") String[] AllDiscipline,
Model model) {
List<Integer> list = Arrays.stream(AllDiscipline).map(Integer::parseInt).collect(Collectors.toList());
List<Discipline> disciplineSemestrList = service.getDisciplineList(list);
semestr.setDisciplineList(disciplineSemestrList);
service.saveNewSemester(semestr);
return "redirect:/semestr";
}
Here is my entity Discipline :
package com.kushnirmark.spring.project.entity;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
#Entity
#Table(name = "discipline")
public class Discipline {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "discipline")
private String discipline;
#Column(name = "status")
private boolean status = true;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "semestr_discipline",
joinColumns = #JoinColumn(name = "id_discipline"),
inverseJoinColumns = #JoinColumn(name = "id_semestr")
)
private List<Semestr> semestrList;
public void addSemesterToDiscipline(Semestr semestr) {
if (semestrList == null) {
semestrList = new ArrayList<>();
}
semestrList.add(semestr);
}
public Discipline() {
}
public Discipline(int id, String discipline, boolean status) {
this.id = id;
this.discipline = discipline;
this.status = status;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDiscipline() {
return discipline;
}
public void setDiscipline(String discipline) {
this.discipline = discipline;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public List<Semestr> getSemestrList() {
return semestrList;
}
public void setSemestrList(List<Semestr> semestrList) {
this.semestrList = semestrList;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Discipline that = (Discipline) o;
return id == that.id &&
status == that.status &&
Objects.equals(discipline, that.discipline);
}
#Override
public int hashCode() {
return Objects.hash(id, discipline, status);
}
#Override
public String toString() {
return "Discipline{" +
"id=" + id +
", discipline='" + discipline + '\'' +
", status=" + status +
'}';
}
}
I am trying to create two entities which have many-to-many relation between them. First entity is Person with PID as primary key, second is Serie with SID as primary key. In database there is a table TJV_5_SERIE_2_PERSON, which represents many to many relationship between these entities.
tables in database
The problem is when I retrieve any entity, Collection annotated with #ManyToMany is always empty. So I assume I've messed up something in my code that explains why my many-to-many relation doesn't work.
I retrieve these two entities by generating (in Netbeans 9.0) 'Restful Web Services from Entity classes'. This way I can use these services to retrieve all attributes succesfully, except Collection with #ManyToMany annotation is always empty.
Any idea why it is not woking appreciated. It is first time trying this, so pardon me for any dumm mistakes.
Person class:
#Entity
#Table(name = "TJV_5_PERSON")
#XmlRootElement
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "PID")
private Integer id;
#Column(name = "PNAME")
private String name;
#ManyToMany()
#JoinTable(
name = "TJV_5_SERIE_2_PERSON",
joinColumns = #JoinColumn(name = "PID", referencedColumnName = "PID"),
inverseJoinColumns = #JoinColumn(name = "SID", referencedColumnName = "SID")
)
// always empty
private Collection<Serie> favourites = new ArrayList<Serie>();
public Person() {
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlTransient
public Collection<Serie> getFavourites() {
return favourites;
}
public void setFavourites(Collection<Serie> favourites) {
this.favourites = favourites;
}
#Override
public int hashCode() {
int hash = 5;
hash = 31 * hash + Objects.hashCode(this.id);
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if (!Objects.equals(this.id, other.id)) {
return false;
}
return true;
}
#Override
public String toString() {
return "Person{" + "id=" + id + ", name=" + name + ", favourites=" + favourites + '}';
}
}
Serie class:
#Entity
#Table(name = "TJV_5_SERIE")
#XmlRootElement
public class Serie implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "SID")
private Integer id;
#Column(name = "STITLE")
private String title;
// always empty
#ManyToMany(mappedBy = "favourites")
private Collection<Person> fans = new ArrayList<Person>();
public Serie() {
}
public Serie(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#XmlTransient
public Collection<Person> getFans() {
return fans;
}
public void setFans(Collection<Person> fans) {
this.fans = fans;
}
#Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + Objects.hashCode(this.id);
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Serie other = (Serie) obj;
if (!Objects.equals(this.id, other.id)) {
return false;
}
return true;
}
#Override
public String toString() {
return "Serie{" + "id=" + id + ", title=" + title + ", fans=" + fans + '}';
}
}
I am not 100% sure, but you may not retrieving any results beacuse of #XMLTransiet annotation above the Serie.class method
#XmlTransient
public Collection<Person> getFans() {
return fans;
}
Try to look in documentation https://docs.oracle.com/javaee/6/api/javax/xml/bind/annotation/XmlTransient.html or in connected posts Hide an entity variable from xml message - #XmlTransient not working
The other issue is cascading data between two corresponding #ManyToMany tables. It means that you have intersection and the data appears in this table automatically when you use some type of cascade but you need send a POST request. It means in your service class layer you can create a method responsible for creating Person and assign a Serie to this Person object which is a foreign key. The article about cascading is here :) https://vladmihalcea.com/a-beginners-guide-to-jpa-and-hibernate-cascade-types/
I'm trying to set up save entity with children together, but I can't find how it is works, I tried to do like in all tutorials but always had a error detached entity passed to persist
this is my entities:
#Entity
#Table(name = "CurriculumVitaes")
public class CurriculumVitae {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotBlank
private String title;
private String summary;
#OneToMany(mappedBy = "curriculumVitae", targetEntity = Education.class, cascade={CascadeType.ALL})
private List<Education> educations = new ArrayList<>();
public CurriculumVitae(){}
public CurriculumVitae(Long id, String title, String summary){
this.id = id;
this.title = title;
this.summary = summary;
}
public void addEducation(Education education) {
if(this.educations.contains(education)){
return;
}
this.educations.add(education);
education.setCurriculumVitae(this);
}
public void removeEducation(Education education){
if(this.educations.contains(education)){
return;
}
this.educations.remove(education);
education.setCurriculumVitae(null);
}
public boolean equals(Object object) {
if (object == this)
return true;
if ((object == null) || !(object instanceof CurriculumVitae))
return false;
final CurriculumVitae a = (CurriculumVitae)object;
if (id != null && a.getId() != null) {
return id.equals(a.getId());
}
return false;
}
}
and child entity:
#Entity
#Table(name = "Educations")
public class Education {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotBlank
private String title;
private String areaOfStudy;
private String description;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "curriculumVitaeId", referencedColumnName = "id")
private CurriculumVitae curriculumVitae;
public Education(){}
public Education(String title, String areaOfStudy, String description){
this.title = title;
this.areaOfStudy = areaOfStudy;
this.description = description;
}
public CurriculumVitae getCurriculumVitae() {
return curriculumVitae;
}
public void setCurriculumVitae(CurriculumVitae curriculumVitae) {
//prevent endless loop
if (sameAsFormer(curriculumVitae))
return ;
//set new owner
CurriculumVitae oldOwner = this.curriculumVitae;
this.curriculumVitae = curriculumVitae;
//remove from the old owner
if (oldOwner!=null)
oldOwner.removeEducation(this);
//set myself into new owner
if (curriculumVitae!=null)
curriculumVitae.addEducation(this);
}
private boolean sameAsFormer(CurriculumVitae newOwner) {
return this.curriculumVitae==null? newOwner == null : this.curriculumVitae.equals(newOwner);
}
public boolean equals(Object object) {
if (object == this)
return true;
if ((object == null) || !(object instanceof Education))
return false;
final Education a = (Education)object;
if (id != null && a.getId() != null) {
return id.equals(a.getId());
}
return false;
}
}
How can I set up save entities all together with one repository method save?
without cascade it will not save inner entities.
#PostMapping
public #ResponseBody CurriculumVitaeViewModel addCurriculumVitae(#RequestBody SaveCurriculumVitaeRequest model){
CurriculumVitae newCv = new CurriculumVitae();
curriculumVitaeModelMapper.Map(model, newCv);
for (EducationViewModel ed:model.getEducations()
) {
Education newEd = new Education();
educationModelMapper.Map(ed, newEd);
newCv.addEducation(newEd);
}
CurriculumVitae savedCv = curriculumVitaeRepository.save(newCv);
i have the following RESTfull method :
#RequestMapping(value = "/budgetLines",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public void create(#RequestBody BudgetLine budgetLine) {
System.out.println("Before Persisting in the repository " + budgetLine);
budgetLineRepository.save(budgetLine);
}
I'am consuming this method inside a web application, i checked using the network analysis tool (in the web developper tool of chrome) that the object sended is valid (all attribute except the id were set with a valid value), but then the object passed to the repository contains only null attributes.
here is an example body :
{
"Name":"testLabel",
"Label":"testName",
"AnnualBudget":9000
}
the class BudgetLine is defined as follows:
#Entity
#Table(name = "T_BUDGETLINE")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class BudgetLine implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "label")
private String Label;
#Column(name = "name")
private String Name;
#Column(name = "annual_budget", precision=10, scale=2)
private BigDecimal AnnualBudget;
#OneToMany(mappedBy = "budgetLine")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Report> reportss = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLabel() {
return Label;
}
public void setLabel(String Label) {
this.Label = Label;
}
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
public BigDecimal getAnnualBudget() {
return AnnualBudget;
}
public void setAnnualBudget(BigDecimal AnnualBudget) {
this.AnnualBudget = AnnualBudget;
}
public Set<Report> getReportss() {
return reportss;
}
public void setReportss(Set<Report> Reports) {
this.reportss = Reports;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BudgetLine budgetLine = (BudgetLine) o;
if (id != null ? !id.equals(budgetLine.id) : budgetLine.id != null) return false;
return true;
}
#Override
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
#Override
public String toString() {
return "BudgetLine{" +
"id=" + id +
", Label='" + Label + "'" +
", Name='" + Name + "'" +
", AnnualBudget='" + AnnualBudget + "'" +
'}';
}
public BudgetLine() {
}
}
Try with first letter in lowercase for parameters
{
"name":"testLabel",
"label":"testName",
"annualBudget":9000
}
Spring relies heavily on standard Java naming conventions, so I suggest you also follow them. In your example, you should name your class fields with lowercased first letter.
I am not getting how to write Hibernate criteria query to achieve the result similar to the result obtained by below SQL query. Please suggest me what are all steps need to be followed to achieve the result.
SELECT PRODUCT.PRODUCTNAME, ITEM.ITEMNAME
FROM PRODUCT_ITEM
JOIN PRODUCT
ON PRODUCT_ITEM.ID = PRODUCT.ID
JOIN ITEM
ON PRODUCT_ITEM.ID = ITEM.ID
Above is my Sql Query to fetch the product_name and item_name. It is working correctly.
I tried get the same result using HIBERNATE CRITERIA QUERY.
Criteria criteria = session.createCriteria(ProductItem.class,"pi");
criteria.createAlias("pi.pk.product", "pip");
criteria.createAlias("pi.pk.item", "pii");
criteria.setProjection(Projections.projectionList().add(Projections.property("pip.id")).add(Projections.property("pii.id")));
List<Object[]> list = criteria.list();
i am getting error saying
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.loader.Loader.doList(Loader.java:2147)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2028)
at org.hibernate.loader.Loader.list(Loader.java:2023)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:95)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1569)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at checkComposite.main(checkComposite.java:38)
Caused by: org.postgresql.util.PSQLException: ERROR: missing FROM-clause entry for table "pip1_"
Position: 8
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:304)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:186)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1668)
at org.hibernate.loader.Loader.doQuery(Loader.java:662)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
at org.hibernate.loader.Loader.doList(Loader.java:2144)
Here my ENTITYS are as below.
#Entity
#Table(name = "item")
public class Item {
private Integer id;
private String name;
private List<ProductItem> productItems = new LinkedList<ProductItem>();
public Item() {
}
#Id
#GenericGenerator(name = "generator", strategy = "increment")
#GeneratedValue(generator = "generator")
#Column(name = "item_id", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.item")
public List<ProductItem> getProductItems() {
return this.productItems;
}
public void setProductItems(List<ProductItem> productItems) {
this.productItems = productItems;
}
}
Product Entity
#Entity
#Table(name = "product")
public class Product {
private Integer id;
private String name;
private List<ProductItem> productItems = new LinkedList<ProductItem>();
public Product() {
}
#Id
#GenericGenerator(name = "generator", strategy = "increment")
#GeneratedValue(generator = "generator")
#Column(name = "product_id", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.product")
public List<ProductItem> getProductItems() {
return this.productItems;
}
public void setProductItems(List<ProductItem> productItems) {
this.productItems = productItems;
}
}
PRODUCT_ITEM entity.
#Entity
#Table(name = "product_item")
#AssociationOverrides({
#AssociationOverride(name = "pk.item", joinColumns = #JoinColumn(name = "item_id")),
#AssociationOverride(name = "pk.product", joinColumns = #JoinColumn(name = "product_id"))
})
public class ProductItem {
private ProductItemPk pk = new ProductItemPk();
#EmbeddedId
private ProductItemPk getPk() {
return pk;
}
private void setPk(ProductItemPk pk) {
this.pk = pk;
}
#Transient
public Item getItem() {
return getPk().getItem();
}
public void setItem(Item item) {
getPk().setItem(item);
}
#Transient
public Product getProduct() {
return getPk().getProduct();
}
public void setProduct(Product product) {
getPk().setProduct(product);
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductItem that = (ProductItem) o;
if (getPk() != null ? !getPk().equals(that.getPk()) : that.getPk() != null) return false;
return true;
}
public int hashCode() {
return (getPk() != null ? getPk().hashCode() : 0);
}
}
Embedable Class is as below.
#Embeddable
public class ProductItemPk implements Serializable {
private Item item;
private Product product;
#ManyToOne
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
#ManyToOne
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductItemPk that = (ProductItemPk) o;
if (item != null ? !item.equals(that.item) : that.item != null) return false;
if (product != null ? !product.equals(that.product) : that.product != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (item != null ? item.hashCode() : 0);
result = 31 * result + (product != null ? product.hashCode() : 0);
return result;
}
}
Try changing the query to:
Criteria criteria = session.createCriteria(ProductItem.class,"pi");
criteria.createAlias("pi.pk", "pipk");
criteria.createAlias("pipk.product", "pip");
criteria.createAlias("pipk.item", "pii");
criteria.setProjection(Projections.projectionList().add(Projections.property("pip.id")).add(Projections.property("pii.id")));
List<Object[]> list = criteria.list();