I'm facing the following problem. Imagine this data model:
As you can see project_function entity is association many to many entity.
Here are my entity classes.
PeronalCard:
#Entity
#Table(name = "personal_card")
#XmlRootElement
public class PersonalCard implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_person")
private Integer idPerson;
/* SOME OTHER ATTRIBUTES */
#OneToMany(cascade = CascadeType.ALL, mappedBy = "projectFunctionPK.personalCard")
private Set<ProjectFunction> projectFunctionSet;
public PersonalCard() {
}
public Integer getIdPerson() {
return idPerson;
}
public void setIdPerson(Integer idPerson) {
this.idPerson = idPerson;
}
#XmlTransient
public Set<ProjectFunction> getProjectFunctionSet() {
return projectFunctionSet;
}
public void setProjectFunctionSet(Set<ProjectFunction> projectFunctionSet) {
this.projectFunctionSet = projectFunctionSet;
}
#Override
public int hashCode() {
int hash = 0;
hash += (idPerson != null ? idPerson.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof PersonalCard)) {
return false;
}
PersonalCard other = (PersonalCard) object;
if ((this.idPerson == null && other.idPerson != null) || (this.idPerson != null && !this.idPerson.equals(other.idPerson))) {
return false;
}
return true;
}
}
Project:
#Entity
#Table(name = "project")
#XmlRootElement
public class Project implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_project")
private Integer idProject;
/* OTHER ATTRIBUTES*/
#OneToMany(cascade = CascadeType.ALL, mappedBy = "projectFunctionPK.project")
private Set<ProjectFunction> projectFunctionSet;
public Project() {
}
public Integer getIdProject() {
return idProject;
}
public void setIdProject(Integer idProject) {
this.idProject = idProject;
}
#XmlTransient
public Set<ProjectFunction> getProjectFunctionSet() {
return projectFunctionSet;
}
public void setProjectFunctionSet(Set<ProjectFunction> projectFunctionSet) {
this.projectFunctionSet = projectFunctionSet;
}
#Override
public int hashCode() {
int hash = 0;
hash += (idProject != null ? idProject.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Project)) {
return false;
}
Project other = (Project) object;
if ((this.idProject == null && other.idProject != null) || (this.idProject != null && !this.idProject.equals(other.idProject))) {
return false;
}
return true;
}
}
ProjectFunction:
#Entity
#Table(name = "project_function")
#XmlRootElement
#AssociationOverrides({
#AssociationOverride(name = "projectFunctionPK.project",
joinColumns = #JoinColumn(name = "id_project", referencedColumnName = "id_project")),
#AssociationOverride(name = "projectFunctionPK.personalCard",
joinColumns = #JoinColumn(name = "id_person", referencedColumnName = "id_person")) })
public class ProjectFunction implements Serializable {
private static final long serialVersionUID = 1L;
protected ProjectFunctionPK projectFunctionPK;
private Date fromd;
private Date tod;
public ProjectFunction() {
this.projectFunctionPK = new ProjectFunctionPK();
}
#EmbeddedId
public ProjectFunctionPK getProjectFunctionPK() {
return projectFunctionPK;
}
public void setProjectFunctionPK(ProjectFunctionPK projectFunctionPK) {
this.projectFunctionPK = projectFunctionPK;
}
#Column(name = "fromd")
#Temporal(TemporalType.DATE)
public Date getFromd() {
return fromd;
}
public void setFromd(Date fromd) {
this.fromd = fromd;
}
#Column(name = "tod")
#Temporal(TemporalType.DATE)
public Date getTod() {
return tod;
}
public void setTod(Date tod) {
this.tod = tod;
}
#Transient
public Project getProject() {
return projectFunctionPK.getProject();
}
public void setProject(Project project) {
this.projectFunctionPK.setProject(project);
}
#Transient
public PersonalCard getPersonalCard() {
return this.projectFunctionPK.getPersonalCard();
}
public void setPersonalCard(PersonalCard personalCard) {
//this.personalCard = personalCard;
this.projectFunctionPK.setPersonalCard(personalCard);
}
#Override
public int hashCode() {
int hash = 0;
hash += (projectFunctionPK != null ? projectFunctionPK.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ProjectFunction)) {
return false;
}
ProjectFunction other = (ProjectFunction) object;
if ((this.projectFunctionPK == null && other.projectFunctionPK != null) || (this.projectFunctionPK != null && !this.projectFunctionPK.equals(other.projectFunctionPK))) {
return false;
}
return true;
}
}
And finally my embedded Primary Key ProjectFunctionPK:
#Embeddable
public class ProjectFunctionPK implements Serializable {
#ManyToOne
private Project project;
#ManyToOne
private PersonalCard personalCard;
public ProjectFunctionPK() {
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public PersonalCard getPersonalCard() {
return personalCard;
}
public void setPersonalCard(PersonalCard personalCard) {
this.personalCard = personalCard;
}
#Override
public int hashCode() {
int hash = 3;
hash = 41 * hash + Objects.hashCode(this.project);
hash = 41 * hash + Objects.hashCode(this.personalCard);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ProjectFunctionPK other = (ProjectFunctionPK) obj;
if (!Objects.equals(this.project, other.project)) {
return false;
}
if (!Objects.equals(this.personalCard, other.personalCard)) {
return false;
}
return true;
}
}
First I save the Project. It works fine. Then i want to connect it using project_function - so I create project_function set them existing project and personal_card and after trying to persist I get following error:
Caused by: org.postgresql.util.PSQLException: ERROR: column projectfun0_.personalcard does not exist
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.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:82)
... 119 more
So apparently Hibernate does not know projectfun0_.personalcard . But I dont know why. Do you see any error in the entity classes? Or could the error possibly be somewhere else ?
Thank you very much for all your answers :)
EmbeddedId documentation
Relationship mappings defined within an embedded id class are not supported.
So, ProjectFunctionPK should contain only basic mappings, and entity mappings should be done in the entity itself. Here are some related posts
https://stackoverflow.com/a/9760808/4074715
https://stackoverflow.com/a/4692144/4074715
Related
I have 2 entities namely Teacher and Club, I need to retrieve the teacher data along with its related club and/or sports.
I a bit new to JPA so am having trouble debugging the stack overflow error I get when I use the findAll method on the Teacher repository.
I had tried adding #JsonIgnore annotation to my one-to-many annotation to deal with the recursion problem as suggested in some similar questions but was still getting problems and am not sure how exactly it's supposed to solve the problem.
TEACHER ENTITY:
#Entity
#Table(name = "TEACHER")
public class Teacher {
private String id;
private String name;
private Collection<ClubTeacher> clubTeachersById;
#Id
#Column(name = "Id", nullable = false, length = 10)
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Basic
#Column(name = "NAME", nullable = true, length = 25)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Teacher teacher = (Teacher) o;
if (id != null ? !id.equals(teacher.id) : teacher.id != null) return false;
if (name != null ? !name.equals(teacher.name) : teacher.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
#OneToMany(mappedBy = "TICClub" ,fetch = FetchType.EAGER)
public Collection<ClubTeacher> getClubTeachersById() {
return clubTeachersById;
}
public void setClubTeachersById(Collection<ClubTeacher> clubTeachersById) {
this.clubTeachersById = clubTeachersById;
}
}
CLUB ENTITY:
#Entity
#Table(name = "CLUB_TEACHER", schema = "abbc", catalog = "")
#IdClass(ClubTeacherPK.class)
public class ClubTeacher implements Serializable {
private String tic;
private String clubkey;
private Teacher teacherByTic;
#Id
#Column(name = "TIC", nullable = false, length = 10)
public String getTic() {
return tic;
}
public void setTic(String tic) {
this.tic = tic;
}
#Id
#Column(name = "CLUBKEY", nullable = false, length = 25)
public String getClubkey() {
return clubkey;
}
public void setClubkey(String clubkey) {
this.clubkey = clubkey;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClubTeacher that = (ClubTeacher) o;
if (tic != null ? !tic.equals(that.tic) : that.tic != null) return false;
if (clubkey != null ? !clubkey.equals(that.clubkey) : that.clubkey != null) return false;
return true;
}
#Override
public int hashCode() {
int result = tic != null ? tic.hashCode() : 0;
result = 31 * result + (clubkey != null ? clubkey.hashCode() : 0);
return result;
}
#ManyToOne
#JoinColumn(name = "TIC", referencedColumnName = "Id", nullable = false,insertable=false, updatable=false)
public Teacher getTeacherByTic() {
return teacherByTic;
}
public void setTeacherByTic(Teacher teacherByTic) {
this.teacherByTic = teacherByTic;
}
}
STACK TRACE:
2021-02-17 21:42:56.516 ERROR 20546 --- [nio-3005-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError: null
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.6.jar:na]
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:1027) ~[gson-2.8.6.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.6.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) ~[gson-2.8.6.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.6.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.6.jar:na]
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97) ~[gson-2.8.6.jar:na]
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61) ~[gson-2.8.6.jar:na]
....
So, I've got an existing ManyToMany relationship set up in my spring application. It appears that I made a mistake by setting this up using the #ManyToMany annotation, because now I need to add a field to the join table, and this does not appear to be an easy feat.
My structure is shipments and products. The shipment table stores information about who the shipment was sent to, what date it was sent, etc. The product table stores information about the product, who makes it, description, size, etc.
What I failed to consider when building this out was, I will need to track quantity of product shipped when I create a shipment, which should be done on the join table.
I've been working along with this example: https://vladmihalcea.com/the-best-way-to-map-a-many-to-many-association-with-extra-columns-when-using-jpa-and-hibernate/
UPDATE:
I've been working through the example above and have run into an issue with infinite recursive calls between the product and shipment tables. My structure is as follows:
ShipmentProductID.java:
// Package and Imports here
#Embeddable
public class ShipmentProductId
implements Serializable {
#Column(name = "product_id")
private Long productId;
#Column(name = "shipment_id")
private Long shipmentId;
private ShipmentProductId() {}
public ShipmentProductId(
Long productId,
Long shipmentId) {
this.productId = productId;
this.shipmentId = shipmentId;
}
// Getters and Setters here
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ShipmentProductId that = (ShipmentProductId) o;
return Objects.equals(productId, that.productId) &&
Objects.equals(shipmentId, that.shipmentId);
}
#Override
public int hashCode() {
return Objects.hash(productId, shipmentId);
}
}
ShipmentProduct.java:
// Package and Imports here
#Entity(name = "ShipmentProduct")
#Table(name = "shipment_product")
public class ShipmentProduct {
#EmbeddedId
private ShipmentProductId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("productId")
private Product product;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("shipmentId")
private Shipment shipment;
#Column(name = "created_on")
private Date createdOn = new Date();
private ShipmentProduct() {}
public ShipmentProduct(Product product, Shipment shipment) {
this.product = product;
this.shipment = shipment;
this.id = new ShipmentProductId(product.getId(),
shipment.getId());
}
// Getters and Setters here
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ShipmentProduct that = (ShipmentProduct) o;
return Objects.equals(product, that.product) &&
Objects.equals(shipment, that.shipment);
}
#Override
public int hashCode() {
return Objects.hash(product, shipment);
}
}
Product.java:
// Package and Imports here
#Entity
#Data
#Cache( usage = CacheConcurrencyStrategy.READ_WRITE )
public class Product extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#JsonIgnoreProperties("products")
// Have tried #JsonIgnore as well
#OneToMany(
mappedBy = "product",
orphanRemoval = true
)
private List<ShipmentProduct> shipments = new ArrayList<>();
#NotNull
private Integer quantity;
public boolean isAssociated(Client client){
if( this.client == null || this.client.getId() == null ||
client == null || client.getId() == null ) return
false;
return this.client.getId() == client.getId();
}
public boolean isAssociated(Expression expression){
if( this.expression == null || this.expression.getId() == null
||
expression == null || expression.getId() == null )
return false;
return this.expression.getId() == expression.getId();
}
public void addShipment(Shipment shipment) {
ShipmentProduct shipmentProduct = new ShipmentProduct(this,
shipment);
shipments.add(shipmentProduct);
shipment.getProducts().add(shipmentProduct);
}
public Set<Shipment> getAllShipments(){
Set<Shipment> shipmentList = new HashSet<>();
for (ShipmentProduct shipmentProduct : shipments) {
shipmentList.add(shipmentProduct.getShipment());
}
return shipmentList;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Objects.equals(id, product.id);
}
#Override
public String toString(){
return "";
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
Shipment.java:
// Package and Imports here
#Entity
#Data
#ToString(exclude = {"products", "contacts"})
#EqualsAndHashCode(exclude = {"products", "contacts"})
public class Shipment extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonIgnoreProperties("shipments")
#OneToMany(
mappedBy = "shipment",
orphanRemoval = true
)
private List<ShipmentProduct> products = new ArrayList<>();
public Set<Product> getAllProducts(){
Set<Product> productList = new HashSet<>();
for (ShipmentProduct shipmentProduct : products) {
productList.add(shipmentProduct.getProduct());
}
return productList;
}
public void addProduct(Product product) {
ShipmentProduct shipmentProduct = new ShipmentProduct(product,
this);
products.add(shipmentProduct);
product.getShipments().add(shipmentProduct);
}
public void removeProduct(Product product) {
for (Iterator<ShipmentProduct> iterator = products.iterator();
iterator.hasNext(); ) {
ShipmentProduct shipmentProduct = iterator.next();
if (shipmentProduct.getShipment().equals(this) &&
shipmentProduct.getProduct().equals(product)) {
iterator.remove();
shipmentProduct.getProduct().getShipments().remove(shipmentProduct);
shipmentProduct.setShipment(null);
shipmentProduct.setProduct(null);
}
}
}
public Optional<Product> getProductById(Long productId){
Optional<ShipmentProduct> shipmentProduct =
products.stream().filter(product ->
product.getId().equals(productId)).findFirst();
return productId == null ? Optional.empty() :
Optional.of(shipmentProduct.get().getProduct());
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shipment shipment = (Shipment) o;
return Objects.equals(id, shipment.id);
}
#Override
public String toString(){
return "";
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
It seems like I'm getting close, as this appears to be working aside from creating an infinitely large JSON object. I've tried all sorts of combinations of EAGER vs LAZY and JsonIgnore and JsonIgnoreProperties. Any thoughts on how to resolve this? My best guess is some interaction with Lombok, but I have not been able to figure this out.
Looks like I finally figured this out... I removed the following methods:
getAllProducts()
getAllShipments()
and replaced them with:
allProducts()
allShipments()
Having them as getters was always adding them to my return object, and they were not being cut off by #JsonIgnore, or anything else.
Next, I updated ShipmentProduct.java and added #JsonIgnore to both shipment and product, while removing #JsonIgnore and/or #JsonIgnoreProperties from Shipment.java and Product.java.
Then, in order to not receive errors when utilizing allProducts() or allShipments(), I added this to my application.properties file: spring.jackson.serialization.fail-on-empty-beans=false
Once this was all complete, I was also able to keep lombok.
Hopefully this helps somebody else in a similar situation. Also, if anybody has additional constructive criticism, please let me know!
You can keep #ManyToMany annotation, just add the joining table in your db and map it:
#JoinTable(
name = "joining_table",
joinColumns = #JoinColumn(
name = "this_id_in_jt",
referencedColumnName = "this_id"
),
inverseJoinColumns = #JoinColumn(
name = "other_id_in_jt",
referencedColumnName = "other_id"
)
)
#ManyToMany
private List<Other> others;
I am in the middle of developing a JHipster project and I've come to a halt due to what I believe to be mapping issues
My Database has several tables, but the two that affect me here are Study and Publication, where they have a Many to Many relationship.
I need to retrieve the collection of Publications where a study can be published, hence Study is the owner of the relationship, but for some reason, Hibernate don't recognise the attributes I map the relation with.
All of this started trying to solve a lazy connection issue, yes I have been through most posts relating this and I have tried everything that made sense to me.
Here the code of Study:
#Audited
#Entity
#Table(name = "Study")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "study")
public class Study implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "num_sites")
private Integer numSites;
#Column(name = "ref")
private String ref;
#Column(name = "study_type")
private String studyType;
#ManyToMany(fetch = FetchType.LAZY)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "Pub_Study",
joinColumns = #JoinColumn(name="studies_id", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="publications_id", referencedColumnName="id"))
public static Set<Publication> publications = new HashSet<>();
#OneToMany(mappedBy = "study")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<SiteData> siteDatas = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getNumSites() {
return numSites;
}
public void setNumSites(Integer numSites) {
this.numSites = numSites;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public String getStudyType() {
return studyType;
}
public void setStudyType(String studyType) {
this.studyType = studyType;
}
public static Set<Publication> getPublicationss() {
return publications;
}
public void setPublicationss(Set<Publication> publications) {
this.publications = publications;
}
public Set<SiteData> getSiteDatas() {
return siteDatas;
}
public void setSiteDatas(Set<SiteData> siteDatas) {
this.siteDatas = siteDatas;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Study study = (Study) o;
if(study.id == null || id == null) {
return false;
}
return Objects.equals(id, study.id);
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Study{" +
"id=" + id +
", numSites='" + numSites + "'" +
", ref='" + ref + "'" +
", studyType='" + studyType + "'" +
'}';
}
Here the code of Publication:
#Audited
#Entity
#Table(name = "Publication")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "publication")
public class Publication implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "authors")
private String authors;
#Column(name = "first_author")
private String firstAuthor;
#Column(name = "journal")
private String journal;
#Column(name = "pubMedId")
private Integer pubMedId;
#Column(name = "title")
private String title;
#Column(name = "year_publish")
private Integer yearPublish;
#Version
Integer version;
#ManyToMany(fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Study> studies = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAuthors() {
return authors;
}
public void setAuthors(String authors) {
this.authors = authors;
}
public String getFirstAuthor() {
return firstAuthor;
}
public void setFirstAuthor(String firstAuthor) {
this.firstAuthor = firstAuthor;
}
public String getJournal() {
return journal;
}
public void setJournal(String journal) {
this.journal = journal;
}
public Integer getPubMedId() {
return pubMedId;
}
public void setPubMedId(Integer pubMedId) {
this.pubMedId = pubMedId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getYearPublish() {
return yearPublish;
}
public void setYearPublish(Integer yearPublish) {
this.yearPublish = yearPublish;
}
public Set<Study> getStudies() {
return studies;
}
public void setStudies(Set<Study> studys) {
this.studies = studys;
}
public Integer getVersion(){
return version;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Publication publication = (Publication) o;
if(publication.id == null || id == null) {
return false;
}
return Objects.equals(id, publication.id);
}
#Override
public int hashCode() {
return Objects.hashCode(id);
}
#Override
public String toString() {
return "Publication{" +
"id=" + id +
", authors='" + authors + "'" +
", firstAuthor='" + firstAuthor + "'" +
", journal='" + journal + "'" +
", pubMedId='" + pubMedId + "'" +
", title='" + title + "'" +
", yearPublish='" + yearPublish + "'" +
'}';
}
}
Here the Implementation of the query from the Repository package:
public class SiteDataRepositoryImpl implements SiteDataRepositoryCustom{
#PersistenceContext
private EntityManager em;
#Override
public List <SiteDataViewDTO> searchSiteDataByFilter(List<Filter> listFilters) {
TypedQuery<SiteData> query = buildQuery(listFilters);
Hibernate.initialize(Study.publications);
int count=0;
for (Filter filter: listFilters){
if("country".equals(filter.getName()))
query.setParameter(filter.getName(), filter.getQuery());
else if("category".equals(filter.getName()))
query.setParameter(filter.getName(), filter.getQuery());
else if("studyRef".equals(filter.getName()))
query.setParameter(filter.getName(), filter.getQuery());
else if("studyType".equals(filter.getName()))
query.setParameter(filter.getName(), filter.getQuery());
else if("pubMedId".equals(filter.getName()))
query.setParameter(filter.getName(), Integer.valueOf(filter.getQuery()));
count++;
}
List<SiteData> siteDataList = query.getResultList();
List<SiteDataViewDTO> siteDataViewDTOList=new ArrayList<SiteDataViewDTO>();
//temp variables
List<String>tempListTreatments = new ArrayList<String>();
List<String>tempListTitles = new ArrayList<String>();
List<Integer>tempListIdMed = new ArrayList<Integer>();
//filling SiteDataViewDTO list
siteDataList.stream().forEach(sd->{
SiteDataViewDTO temp = new SiteDataViewDTO();
temp.setTypeStudy(sd.getTypeStudy() + "id SiteData: " + sd.getId());
temp.setRef(sd.getStudy().getRef());
temp.setCategory(sd.getCategory().getName());
temp.setUpper95CI(sd.getUpper95CI());
temp.setYearStart(sd.getYearStart());
temp.setYearEnd(sd.getYearEnd());
Set<Publication>setPu = sd.getStudy().getPublicationss();
System.out.println("#################### In the query, size of the Publications List "+setPu.size());
setPu.stream().forEach(sp-> {
tempListTitles.add(sp.getTitle());
tempListIdMed.add(sp.getPubMedId());
});
Set<Treatment>setTr = sd.getTreatments();
/*setTr.stream().forEach(sp-> {
tempListTreatments.add(sp.getTreatmentName());
});*/
temp.setListPubObject(setPu);
temp.setListTreatObject(setTr);
siteDataViewDTOList.add(temp);
});
return siteDataViewDTOList;
}
private TypedQuery<SiteData> buildQuery(List<Filter> listFilters){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SiteData> cq = cb.createQuery(SiteData.class);
Root<SiteData> siteData = cq.from(SiteData.class);
Join<SiteData, Category> cat = siteData.join("category", JoinType.LEFT);
Join<SiteData, Location> loc = siteData.join("location",JoinType.LEFT);
Join<SiteData, Treatment> tre = siteData.join("treatments",JoinType.LEFT);
Join<SiteData, Study> stu = siteData.join("study",JoinType.LEFT);
Join<Study, Publication> pub = stu.join("publications",JoinType.LEFT);
List<Predicate> predicates = new ArrayList<>();
int index = 0;
for(Filter filter : listFilters){
if("country".equals(filter.getName()))
predicates.add(cb.equal(loc.get("country"), cb.parameter(String.class, filter.getName())));
else if("category".equals(filter.getName()))
predicates.add(cb.equal(cat.get("name"), cb.parameter(String.class, filter.getName())));
else if("studyRef".equals(filter.getName()))
predicates.add(cb.equal(stu.get("ref"), cb.parameter(String.class, filter.getName())));
else if("studyType".equals(filter.getName()))
predicates.add(cb.equal(stu.get("studyType"), cb.parameter(String.class, filter.getName())));
else if("pubMedId".equals(filter.getName()))
predicates.add(cb.equal(pub.get("pubMedId"), cb.parameter(Integer.class, filter.getName())));
index++;
}
cq.where(cb.and(predicates.toArray(new Predicate[0])));
return em.createQuery(cq);
}
}
So, if anyone could throw some light on to this, it would be very helpful!
I Edit to add the main exception it throws:
Caused by: org.hibernate.QueryException: could not resolve property: publications of: org.wwarn.vivax.manager.domain.Study
at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:83)
at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:77)
at org.hibernate.persister.entity.AbstractEntityPersister.toType(AbstractEntityPersister.java:1978)
at org.hibernate.hql.internal.ast.tree.FromElementType.getPropertyType(FromElementType.java:367)
You have a typo in your entity definition: "publicationss" instead of "publications". Since Hibernate uses JavaBeans properties for data access, it complains about getPublications() loss in your definition.
Metamodel preserves you from such typos, consider using it.
I'm facing a trouble where I've my transactions controlled by Spring Tx and when I do a merge and after flush, my implementation does not print the command neither the Spring Tx commit them.
Follows my code:
#Named
#Transactional(propagation = Propagation.MANDATORY, readOnly = false)
class AverbacaoDAOImpl extends AbstractDAOImpl<Averbacao, Long> implements AverbacaoDAO{
private List<Averbacao> atualizarAverbacoes(final List<Averbacao> averbacoes, final EtapaAverbacao etapa) {
int counter = 0;
for(Averbacao averbacao : averbacoes) {
averbacao.setEtapa(etapa);
atualizar(averbacao);
counter += 1;
}
entityManager.flush();
LOGGER.debug("Atualizado {} averbacoes para a etapa {}", counter, etapa);
return averbacoes;
}
}
private atualizar(Averbacao averbacao) {
entityManager.merge(averbacao);
}
Every objects in the list are managed by JPA (or I think that they're)
Follows logs:
Spring Transaction/Hibernate:
08:37:06,102 DEBUG [BilhetagemProcessManagerExecutor-1hread] [AbstractFlushingEventListener] Processing flush-time cascades
08:37:07,576 DEBUG [BilhetagemProcessManagerExecutor-1hread] [AbstractFlushingEventListener] Dirty checking collections
08:37:08,703 DEBUG [BilhetagemProcessManagerExecutor-1hread] [Collections] Collection found: [br.com.company.bilhetagem.brms.model.Proposta.propostaTaxaAplicaveis#35340], was: [br.com.company.bilhetagem.brms.model.Proposta.propostaTaxaAplicaveis#35340] (initialized)
08:37:08,706 DEBUG [BilhetagemProcessManagerExecutor-1hread] [AbstractFlushingEventListener] Flushed: 0 insertions, 0 updates, 0 deletions to 26047 objects
08:37:08,707 DEBUG [BilhetagemProcessManagerExecutor-1hread] [AbstractFlushingEventListener] Flushed: 0 (re)creations, 0 updates, 0 removals to 1 collections
08:37:08,707 DEBUG [BilhetagemProcessManagerExecutor-1hread] [EntityPrinter] Listing entities:
08:37:08,707 DEBUG [BilhetagemProcessManagerExecutor-1hread] [EntityPrinter] br.com.company.bilhetagem.brms.model.tarifas.TipoTarifaPercentual{percentualMultiplicador=1.0, tipo=OCD}
08:37:08,713 DEBUG [BilhetagemProcessManagerExecutor-1hread] [EntityPrinter] More......
Averbacao
#Entity
#Table(name = "TBIL_RELAC_AVERB_PROPT", schema = "BILHET")
#SecondaryTable(name = "TBIL_AVERBACAO", schema = "BILHET", pkJoinColumns = { #PrimaryKeyJoinColumn(name = "SEQ_NUMER_AVB") })
public final class Averbacao implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3229114271975034004L;
#Id
#Column(name = "SEQ_NUMER_AVB")
private long numeroAverbacao;
#ManyToOne(optional = false, targetEntity = Proposta.class)
#JoinColumn(name = "SEQ_NUMER_PRS", nullable = false)
private Proposta proposta;
#Column(name = "VLR_IS", scale = 15, precision = 2, nullable = true)
private Double valorIS;
#ManyToOne(optional = false)
#JoinColumn(name = "CTL_LOCAL_ORI", nullable = false, table = "TBIL_AVERBACAO")
private Localidade origem;
#ManyToOne(optional = false)
#JoinColumn(name = "CTL_LOCAL_DES", nullable = false, table = "TBIL_AVERBACAO")
private Localidade destino;
#ManyToOne(optional = true)
#JoinColumn(name = "CTL_LOCAL_FIM", nullable = true, table = "TBIL_AVERBACAO")
private Localidade destinoFinal;
#Column(name = "DHR_EMBAR", nullable = false, table = "TBIL_AVERBACAO")
#Temporal(TemporalType.DATE)
private Date dataEmbarque;
#Column(name = "IDT_CARGA_DSC", nullable = false, table = "TBIL_AVERBACAO")
private char tipoCargaDescarga;
#Column(name = "IDT_VEICU", nullable = false, table = "TBIL_AVERBACAO")
private String tipoVeiculo;
#Column(name = "STA_AVARI", nullable = false, table = "TBIL_AVERBACAO")
private char indicadorAvaria;
#Column(name = "STA_FLUVI", nullable = false, table = "TBIL_AVERBACAO")
private char indicadorTrechoFluvial;
#Column(name = "NUM_ETAPA_AVB", nullable = false, table = "TBIL_AVERBACAO")
#Type(type = "br.com.company.bilhetagem.brms.dao.jpa.types.EtapaAverbacaoUserType")
private EtapaAverbacao etapa;
public Averbacao() {
}
public Averbacao(final Proposta proposta) {
this.proposta = proposta;
}
#Transient
public AverbacaoPropostaKey getAverbacaoPropostaKey() {
final long numeroProposta =
this.proposta == null ? 0 : this.proposta.getNumeroProposta();
return new AverbacaoPropostaKey(this.numeroAverbacao, numeroProposta);
}
public Date getDataEmbarque() {
return new DateTime(dataEmbarque).toDate();
}
public Localidade getDestino() {
return destino;
}
public long getNumeroAverbacao() {
return numeroAverbacao;
}
public Localidade getOrigem() {
return origem;
}
public Proposta getProposta() {
return proposta;
}
public Double getValorIS() {
return valorIS;
}
public char getTipoCargaDescarga() {
return tipoCargaDescarga;
}
public String getTipoVeiculo() {
return tipoVeiculo;
}
public char getIndicadorAvaria() {
return indicadorAvaria;
}
public char getIndicadorTrechoFluvial() {
return indicadorTrechoFluvial;
}
public Localidade getDestinoFinal() {
return destinoFinal;
}
public final EtapaAverbacao getEtapa() {
return etapa;
}
public final void setEtapa(EtapaAverbacao etapa) {
this.etapa = etapa;
}
#Override
public String toString() {
return toStringHelper(this).addValue(this.numeroAverbacao)
.add("Proposta", this.proposta).add("Origem", this.origem)
.add("Destino", this.destino).addValue(this.dataEmbarque)
.addValue(this.valorIS).toString();
}
#Override
public int hashCode() {
return Objects.hashCode(this.dataEmbarque, this.destino,
this.numeroAverbacao, this.origem, this.proposta, this.valorIS,
this.tipoCargaDescarga, this.indicadorAvaria,
this.indicadorTrechoFluvial, this.destinoFinal);
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}
final Averbacao that = (Averbacao) obj;
return equal(this.numeroAverbacao, that.getNumeroAverbacao())
&& equal(this.destino, that.getDestino())
&& equal(this.origem, that.getOrigem())
&& equal(this.proposta, that.getProposta());
}
}
EtapaAverbacao
public enum EtapaAverbacao implements Serializable, PersistentEnum {
NAO_PROCESSADO(1),
PROCESSANDO(2),
PROCESSADO(3);
private int id;
private EtapaAverbacao(final int id) {
this.id = id;
}
#Override
public int getId() {
return this.id;
}
}
public abstract class AbstractPersistentEnumUserType implements UserType {
public AbstractPersistentEnumUserType() {
}
public static List<Integer> toIdList(final List<? extends PersistentEnum> enumList) {
final List<Integer> ids = new ArrayList<Integer>();
if(enumList == null) {
return ids;
}
for(PersistentEnum e : enumList) {
ids.add(e.getId());
}
return ids;
}
public static List<Integer> toIdList(final PersistentEnum[] enumList) {
return toIdList(Arrays.asList(enumList));
}
#Override
public final int[] sqlTypes() {
return new int[] { Types.INTEGER };
}
#Override
public abstract Class<T> returnedClass();
#Override
public final boolean equals(Object obj1, Object obj2) {
if(obj1 == null) {
return false;
}
return obj1.equals(obj2);
}
#Override
public final int hashCode(Object obj) {
return obj == null ? 0 : obj.hashCode();
}
#Override
public final Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws SQLException {
if (rs.wasNull()) {
return null;
}
for (PersistentEnum value : returnedClass().getEnumConstants()) {
final int id = rs.getInt(names[0]);
if (id == value.getId()) {
return value;
}
}
throw new IllegalStateException("Unknown " + returnedClass().getSimpleName() + " id");
}
#Override
public final void nullSafeSet(PreparedStatement stmt, Object value, int index, SessionImplementor session) throws SQLException {
if (value == null) {
stmt.setNull(index, Types.INTEGER);
} else {
stmt.setInt(index, ((PersistentEnum) value).getId());
}
}
#Override
public final Object deepCopy(Object value) {
return value;
}
#Override
public final boolean isMutable() {
return false;
}
#Override
public final Serializable disassemble(Object value) {
return (Serializable) value;
}
#Override
public final Object assemble(Serializable cached, Object owner) {
return cached;
}
#Override
public final Object replace(Object original, Object target, Object owner) {
return original;
}
}
public class EtapaAverbacaoUserType extends
AbstractPersistentEnumUserType<EtapaAverbacao> {
#Override
public Class<EtapaAverbacao> returnedClass() {
return EtapaAverbacao.class;
}
}
After much effort I discovered with my team that the objects returned from query they were fetched as read only.
So, we get out the hint READ_ONLY in the query and now the objects can be updated
I just wanna ask know how its possible to create object after creating your database with Hibernate annotations?
When i run the code below, it creates the database with the objects, but when i run the second time it just creates exactly the same, and none new objects are added? How come? How do i create objects using annotations with the method .save, after creating the database with annotations? Or is it not possible to do so with annotations?
Thanks in advance.
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
Adress adress = new Adress("Streetname", "postcode");
Person person1 = new Person("Peter Hanks", adress);
Person person2 = new Person("Sophie Hanks", adress);
session.save(person1);
session.save(person2);
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
Heres the code person.class
#Entity
#Table(name="person")
public class Person implements Serializable {
private long id;
private String navn;
private Adresse adresse;
public Person() {
}
public Person(String navn, Adresse adresse) {
this.navn = navn;
this.adresse = adresse;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name= "adresse_id", nullable = false)
public Adresse getAdresse() {
return adresse;
}
public void setAdresse(Adresse adresse) {
this.adresse = adresse;
}
#Id
#GeneratedValue
#Column(name= "id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "navn", nullable= false, length= 100)
public String getNavn() {
return navn;
}
public void setNavn(String navn) {
this.navn = navn;
}
#Override
public int hashCode() {
int hash = 3;
hash = 29 * hash + (this.navn != null ? this.navn.hashCode() : 0);
hash = 29 * hash + (this.adresse != null ? this.adresse.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if ((this.navn == null) ? (other.navn != null) : !this.navn.equals(other.navn)) {
return false;
}
if (this.adresse != other.adresse && (this.adresse == null || !this.adresse.equals(other.adresse))) {
return false;
}
return true;
}
You might need to show us how you've written and annotated your Person and Adress (sic) objects.
If you've written "correct" equals() and hashcode() implementations (i.e. that don't look at the #Id of the object) then your save() calls will do nothing the second time around because the objects you've asked to save already exist in the database.
just changed the settings for hibernate.hbm2ddl.auto from create to create-update, and now theres no problem...