I have a many-to-many relationship between EnfInspPrgm entity and EnfInspPmSc entity.
Here are the entity classes
public class EnfInspPrgm implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="PRM_ID")
private long prmId;
#Column(name="AREA_ID")
private long areaId;
//bi-directional many-to-one association to EnfInspPmSc
#OneToMany(mappedBy="enfInspPrgm")
private List<EnfInspPmSc> enfInspPmScs;
public EnfInspPrgm() {
}
public long getPrmId() {
return this.prmId;
}
public void setPrmId(long prmId) {
this.prmId = prmId;
}
public long getAreaId() {
return this.areaId;
}
public void setAreaId(long areaId) {
this.areaId = areaId;
}
public List<EnfInspPmSc> getEnfInspPmScs() {
return this.enfInspPmScs;
}
public void setEnfInspPmScs(List<EnfInspPmSc> enfInspPmScs) {
this.enfInspPmScs = enfInspPmScs;
}
public EnfInspPmSc addEnfInspPmSc(EnfInspPmSc enfInspPmSc) {
getEnfInspPmScs().add(enfInspPmSc);
enfInspPmSc.setEnfInspPrgm(this);
return enfInspPmSc;
}
public EnfInspPmSc removeEnfInspPmSc(EnfInspPmSc enfInspPmSc) {
getEnfInspPmScs().remove(enfInspPmSc);
enfInspPmSc.setEnfInspPrgm(null);
return enfInspPmSc;
}
}
#Entity
#Table(name="ENF_INSP_PM_SC")
public class EnfInspPmSc implements Serializable {
private static final long serialVersionUID = 1L;
//bi-directional many-to-one association to InspectionSource
#ManyToOne(optional=false)
#JoinColumn(name="ENF_INSP_SOURCE_ID")
private InspectionSource inspectionSource;
#Column(name="ENF_INSP_PRM_SRC_ID")
private long enfInspPrmSrcId;
#ManyToOne
#JoinColumn(name="PRM_ID")
private EnfInspPrgm enfInspPrgm;
public EnfInspPmSc() {
}
}
#Entity
#Table(name = "REF_ENF_INSP_SOURCE")
public class InspectionSource implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ENF_INSP_SOURCE_ID")
private Integer id;
// bi-directional many-to-one association to User
#ManyToOne
#JoinColumn(name = "CREATED_BY_USER_ID")
private User createdUser;
// bi-directional many-to-one association to User
#ManyToOne
#JoinColumn(name = "MODIFIED_BY_USER_ID")
private User modifiedUser;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public User getCreatedUser() {
return createdUser;
}
public void setCreatedUser(User createdUser) {
this.createdUser = createdUser;
}
public String getCreatedByName() {
return createdByName;
}
public void setCreatedByName(String createdByName) {
this.createdByName = createdByName;
}
public User getModifiedUser() {
return modifiedUser;
}
public void setModifiedUser(User modifiedUser) {
this.modifiedUser = modifiedUser;
}
}
I am creating a JPA repository for selecting the EnfInspPrgm entities. But itis causing an error
Invalid identifier for enfInspPrgm, ENF_INSP_SOURCE_ID
Please help me and resolve this issue.
Your code seems missing some declaration. For example EnfInspPrgm is not annotatted with #Entity.
Also, In EnfInspPmSc you didn't put getter and setter for the fields. Put getEnfInspPrgm and setEnfInspPrgm. Do the same for the other fields.
Note that JPA declartions will be translated in all cases into native sql. The owner of the relationship is always the many side which has a FK to the one side. So, If EnfInspPmSc don't have those setters and getters you won't be able to get access to any data in both tables.
Related
Is it possible in plain JPA or Hibernate a composite key, where an element of the composite key is a sequence and the other element is a mapped with a foreign key.
I have a composite key in my table and part of it needs to be generated by a sequence.
I tried the following, but it doesn't work
class produit
#Entity
public class Produit{
#EmbeddedId
private ProduitClientPK id=new ProduitClientPK();
private Client client;
public ProduitClientPK getId() {
return id;
}
public void setId(ProduitClientPK id) {
this.id = id;
}
#JsonIgnore
#ManyToOne
#JoinColumn(name="FK_CLIENT")
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
}
class composite key :
#Embeddable
public class ProduitClientPK implements Serializable {
private long fkproduit;
private long clientSeq;
#Column(name = "FK_PRODUIT")
#Id
public long getFkProduit() {
return fkproduit;
}
public void setFkProduit(long fkproduit) {
this.fkproduit= fkproduit;
}
#Column(name = "CLIENT_SEQ")
#Id
public long getclientSeq() {
return clientSeq;
}
public void setClientSeq(long clientSeq) {
this.clientSeq= clientSeq;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PolPolAvnEntityPK that = (PolPolAvnEntityPK) o;
return fkPolice == that.fkPolice &&
avnSeq == that.avnSeq;
}
#Override
public int hashCode() {
return Objects.hash(fkPolice, avnSeq);
}
}
class client :
#Entity
public class Client {
private Long id;
private Set<Produit> produits;
#Id
#Column(name = "ID_PRODUIT")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#OneToMany(mappedBy = "client", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<Produit> getProduits() {
return produits;
}
public void setProduits(Set<Produit> avenants) {
this.produits = produits;
}
public void addProduits(Produit produit){
produit.setClient(this);
produits.add(produit);
}
}
Your model does not make much sense, unless I misunderstood it. Why do you need FK_PRODUIT to be part of the primary key? If you are using a sequence for CLIENT_SEQ, this is enough to make the row unique. Apart from that, shouldn't this CLIENT_SEQ value be generated when persisting a Client? IMO you should be using something like the following:
#Entity
public class Produit{
#Id
#GeneratedValue
private Long id;
private Client client;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonIgnore
#ManyToOne
#JoinColumn(name="FK_CLIENT")
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
}
I've met with the same issue not so long time ago. It would be better not to use #EmbeddedId in your case if you want one of PK fields to be generated by your database. I'm not expert in Hibernate, but as I know Hibernate doesn't try to set values to ID fields only if they are annotated by #GeneratedValue. Only this annotation can tell Hibernate to rely on database sequences. And you cannot do it in Embeddable class.
Try just use one #Id field if you want one to be generated.
I am trying to perform a fetch using Criteria API with restrictions on the variable of an embedded entity. But I am getting the below error,
org.hibernate.QueryException: could not resolve property: cpm of: org.sorabh.SystemEnt
Below is my SystemEnt entity,
#Entity
#Table(name="system")
public class SystemEnt implements Serializable{
#Id
#Column(name="pmTpId", nullable = false)
private int id;
#Column(name="pmMeasureId", nullable = false)
private int pmMeasureId;
#OneToOne(fetch=FetchType.EAGER)
#JoinColumn(name="pmMeasureId", insertable=false, updatable=false)
private Cpm cpm;
private String mapper;
public int getId() {
return id;
}
public int getPmMeasureId() {
return pmMeasureId;
}
public Cpm getCpm() {
return cpm;
}
public String getMapper() {
return mapper;
}
public void setId(int id) {
this.id=id;
}
public void setPmMeasureId(int pmMeasureId) {
this.pmMeasureId=pmMeasureId;
}
public void setCpm(Cpm cpm) {
this.cpm=cpm;
}
public void setMapper(int mapper) {
this.mapper=mapper;
}
My CpmMeas contains
#Entity
#Table(name="cpm")
public class Cpm implements Serializable{
#Id
#Column(name="pmMeasureId", nullable = false)
private int pmMeasureId;
#Column(nullable=false)
private int pmGranularity
//getters and setters
public void setPmMeasureId(int pmMeasureId) {
this.pmMeasureId=pmMeasureId;
}
public int getPmMeasureId() {
return pmMeasureId;
}
public void setPmGranularity(int pmGranularity) {
this.pmGranularity=pmGranularity;
}
public int getPmGranularity() {
return pmGranularity;
}
I do the below in my serviceImpl:
Criteria cr = session.createCriteria(SystemEnt.class);
cr.add(Restrictions.like("mapper", "Test", MatchMode.START));
cr.add(Restrictions.eq("cpm.pmGranularity", 1));
I have tried using aliases as suggested in a few other posts on SO, but it doesn't seem to solve the issue.
Also, it is not having issues in resolving mapper, i.e only the nested entities and corresponding variables are not getting resolved.
Use alias , as
Criteria cr = session.createCriteria(SystemEnt.class);
cr.createAlias("cpm","cpm");
cr.add(Restrictions.like("mapper", "Test", MatchMode.START));
cr.add(Restrictions.eq("cpm.pmGranularity", 1));
anyway the field mapper should be a String, in your sample code it is defined as an int.
I tested and without a doubt it works fine.
I have two DTO objects say A and B which are having getters and setters and are used to take data from the database. The problem is when I am calling A, B gets called and B again points itself to A and a cycle is created.
I cannot ignore/hide the method which is creating the cycle. I need to take the whole data of A and B.
Is there any way to achieve it ?
Please help
This is my code which is causing the problem. This is application DTO which is calling environment DTO
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
And this is environment DTO which is calling the application DTO
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Here cycle is getting created
This is my rest call which will give result in XML format and I think while creating XML cycle is getting created
#GET
#Path("/get")
#Produces({MediaType.APPLICATION_XML})
public List<ApplicationDTO> getAllApplications(){
List<ApplicationDTO> allApplication = applicationService.getAllApplication();
return allApplication;
}
This is the Application DTO class
#Entity
#Table(name="application")
#org.hibernate.annotations.GenericGenerator(
name ="test-increment-strategy",strategy = "increment")
#XmlRootElement
public class ApplicationDTO implements Serializable {
#XmlAttribute
public Long appTypeId;
private static final long serialVersionUID = -8027722210927935073L;
private Long applicationId;
private String applicationName;
private ApplicationTypeDTO applicationType;
private String applicationDescription;
private Integer owner;
private Integer createdBy;
private Integer assignedTo;
private Date createTime;
private Date modifiedTime;
private Set<EnvironmentDTO> environment;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "applicationId")
public Long getApplicationId() {
return applicationId;
}
private void setApplicationId(Long applicationId) {
this.applicationId = applicationId;
}
#Column(name = "applicationName")
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
#ManyToOne(targetEntity=ApplicationTypeDTO.class
,fetch = FetchType.LAZY
)
#JoinColumn(name="applicationType")
public ApplicationTypeDTO getApplicationType() {
return applicationType;
}
public void setApplicationType(ApplicationTypeDTO applicationType) {
this.applicationType = applicationType;
}
#Column(name = "description")
public String getApplicationDescription() {
return applicationDescription;
}
public void setApplicationDescription(String applicationDescription) {
this.applicationDescription = applicationDescription;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Column(name = "createdBy")
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
#Column(name = "assignedTo")
public Integer getAssignedTo() {
return assignedTo;
}
public void setAssignedTo(Integer assignedTo) {
this.assignedTo = assignedTo;
}
#Column(name = "createTime")
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#Column(name = "modifiedTime")
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
This is the Environment DTO class
#Entity
#Table(name="environment")
#org.hibernate.annotations.GenericGenerator(
name = "test-increment-strategy",
strategy = "increment")
#XmlRootElement
public class EnvironmentDTO implements Serializable {
#XmlAttribute
public Long envTypeId;
#XmlAttribute
public Long appId;
private static final long serialVersionUID = -2756426996796369998L;
private Long environmentId;
private String environmentName;
private EnvironmentTypeDTO environmentType;
private Integer owner;
private Date createTime;
private Set<InstanceDTO> instances;
private ApplicationDTO application;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "envId")
public Long getEnvironmentId() {
return environmentId;
}
private void setEnvironmentId(Long environmentId) {
this.environmentId = environmentId;
}
#Column(name = "envName")
public String getEnvironmentName() {
return environmentName;
}
public void setEnvironmentName(String environmentName) {
this.environmentName = environmentName;
}
#ManyToOne(targetEntity=EnvironmentTypeDTO.class)
#JoinColumn(name = "envType")
public EnvironmentTypeDTO getEnvironmentType() {
return environmentType;
}
public void setEnvironmentType(EnvironmentTypeDTO environmentType) {
this.environmentType = environmentType;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Temporal(TemporalType.DATE)
#Column(name = "createTime")
public Date getCreateTime()
{
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#OneToMany(mappedBy="environment", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
public Set<InstanceDTO> getInstances() {
return instances;
}
public void setInstances(Set<InstanceDTO> instances) {
this.instances = instances;
}
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
//#XmlTransient
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Your object graph is cyclic. There is nothing intrinsically wrong with that, and it is a natural consequence of using JPA.
Your problem is not that your object graph is cyclic, but that you are encoding it in a format which cannot handle cycles. This isn't a Hibernate question, it's a JAXB question.
My suggestion would be to stop JAXB from attempting to marshal the application property of the EnvironmentDTO class. Without that property the cyclic graph becomes a tree. You can do this by annotating that property with #XmlTransient.
(confession: i learned about this annotation by reading a blog post by Mr Doughan, which i came across after reading his answer to this question!)
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
MOXy offers the #XmlInverseReference extension to handle this use case. Below is an example of how to apply this mapping on two entities with a bidirectional relationship.
Customer
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
Address
import javax.persistence.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
public class Address implements Serializable {
#Id
private long id;
#OneToOne
#JoinColumn(name="ID")
#MapsId
#XmlInverseReference(mappedBy="address")
private Customer customer;
}
For More Information
http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html
http://blog.bdoughan.com/2013/03/moxys-xmlinversereference-is-now-truly.html
My advice is not exposing your JPA entity class to your webservices. You can create different POJO class and convert your JPA entity to the POJO. For example:
this is your JPA entity
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
you should use this class for your webservices:
public class CustomerModel{
private long id;
//you can call different WS to get the Address class, or combine to this model
public void setFromJpa(Customer customer){
this.id = customer.id;
}
}
I am trying to implement a tagging system in my database (MySQL V5.1.61), and then get that working in hibernate. Here are the relevant parts of my database:
And the data contained:
If I am doing this correctly, then 'nir' should have 3 tags associated with him, 'Food','Sorority', and 'Summer Internship'.
What I am having trouble with is implementing this relationship in hibernate (Using annotations):
The UserHibernate class (I'm using GWT so I need separate hibernate and DTO objects):
#Entity
#Table(name="user")
public class UserHibernate implements Serializable{
private int ID;
//removed fields for brevity
private Set<UserTagsHibernate> tags;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "uID")
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
/**
* #return the tags
*/
#OneToMany(mappedBy="user", fetch=FetchType.EAGER)
public Set<UserTagsHibernate> getTags() {
return tags;
}
/**
* #param tags the tags to set
*/
public void setTags(Set<UserTagsHibernate> tags) {
this.tags = tags;
}
}
The UserTagsHibernate Class:
#Entity
#Table(name="usertags")
public class UserTagsHibernate {
private int usertagsID;
private UserHibernate user;
private TagsHibernate tags;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="userforeignkey")
public UserHibernate getUser() {
return user;
}
public void setUser(UserHibernate userHibernate) {
this.user = userHibernate;
}
#OneToOne
#JoinColumn(name="tagforeignkey")
public TagsHibernate getTags() {
return tags;
}
public void setTags(TagsHibernate tagsHibernate) {
this.tags = tagsHibernate;
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "usertagsID")
public int getUsertagsID() {
return usertagsID;
}
public void setUsertagsID(int usertagsID) {
this.usertagsID = usertagsID;
}
}
The TagsHibernate Class:
#Entity
#Table(name = "tags")
public class TagsHibernate {
private int tagID;
//removed for brevity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "tagID")
public int getTagID() {
return tagID;
}
public void setTagID(int tagID) {
this.tagID = tagID;
}
}
The problem that I am having is that when I try and retrieve a user, here 'nir', he shows up three times. I believe it is because he has 3 tags, so for some reason, when I issue the query "session.createCriteria(UserHibernate.class).add(Restrictions.eq("username", "nir")).list();" I get a list of length 3. Any ideas why this is happening?
This problem pops up all the time when using the Criteria API...it's a known quirk. The workarounds are either to use HQL instead or to add a transformer that filters out the duplicates like so:
session.createCriteria(UserHibernate.class)
.add(Restrictions.eq("username", "nir"))
.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
.list();
I have the following domain classes:
#Entity
#Table(name="ADDRESSBOOK_FIELD")
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class AbstractAddressbookField {
private int dbID;
private Addressbook addressbook;
public AbstractAddressbookField() {
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return dbID;
}
public void setId(int id) {
this.dbID = id;
}
#ManyToOne
#JoinColumn(nullable=false)
public Addressbook getAddressbook() {
return addressbook;
}
public void setAddressbook(Addressbook addressbook) {
this.addressbook = addressbook;
}
}
.
#Entity
#Table(name="DATE_FIELD")
public class DateField extends AbstractAddressbookField {
public DateField() {
}
}
.
#Entity
#Table(name="NEW_ADDRESSBOOK")
public class Addressbook {
private int dbID;
private Set<DateField> dateFields = new HashSet<DateField>();
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getDbID() {
return dbID;
}
public void setDbID(int dbID) {
this.dbID = dbID;
}
#OneToMany(mappedBy="Addressbook", cascade={CascadeType.ALL})
public Set<DateField> getDateFields() {
return dateFields;
}
public void setDateFields(Set<DateField> dateFields) {
this.dateFields = dateFields;
}
}
My packages are being scanned correctly to pick up all the mappings, but I am getting the following exception:
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: fields.DateField
I am unsure as to why this is, as the class is clearly mapped to.
Looks like that entity is not mapped in your ' persistence.xml' file.
I think you problem is the capital letter in:
#OneToMany(mappedBy="Addressbook", cascade={CascadeType.ALL})
public Set<DateField> getDateFields() {
return dateFields;
}
use mappedBy="addressbook instead.