JPA: How can I Select #Embeddable Class - java

I will select all the columns from #Embeddable Class Certification. But i cann't select it. how can i do select the Embeddable class.
#Entity
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#ElementCollection
#CollectionTable(name = "Certification", joinColumns = {#JoinColumn(name="user_id")})
private List<Certification> certifications = new ArrayList<Certification>();
public List<Certification> getCertifications() {
return certifications;
}
public void setCertifications(List<Certification> certifications) {
this.certifications = certifications;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
.....
#Embeddable Class Certification
#Embeddable
public class Certification{
private String name;
private String certArt;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCertArt() {
return certArt;
}
public void setCertArt(String certArt) {
this.certArt = certArt;
}
......
If i run the ResultService i get the following exception:
Caused by: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [select c from Certification c]. Unknown entity type [Certification].
How can i select the #Embeddable Class?

You would need to retrieve Certification via the real Entity class i.e. Department. One example query could be as below:
select cer from Department dep join dep.certifications cer
Alternatively, you may want to retrieve qualifying Department entities and then fetch certifications using them.

Related

Save at the same time an composed object using JpaRepository

Can I save an object that contains another object directly in the database?
My back-end structure is like this:
Rest services
Services
Repository (extends JpaRepository)
Model
Suppose that I have two entity in my model: Company and Address. Both generated by the JPA tool provided by IntelliJ.
Company class model
#Entity
public class Company {
private int idcompany;
private String name;
private Address address;
#Id
#Column(name = "idcompany")
public int getIdcompany() {
return idcompany;
}
public void setIdcompany(int idcompany) {
this.idcompany = idcompany;
}
#Basic
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne
#JoinColumn(name = "idaddress", referencedColumnName = "idaddress", nullable = false)
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address class model
#Entity
public class Address {
private long idaddress;
private String zip;
#Id
#Column(name = "idaddress")
public long getIdaddress() {
return idaddress;
}
public void setIdaddress(long idaddress) {
this.idaddress = idaddress;
}
#Basic
#Column(name = "zip")
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
}
Moreover, both entities have an interface that extends the interface JpaRepository<T,ID>. So, I have CompanyRepository and AddressRepository. I use these two interfaces in they respective Service classes: CompanyService and AddressService. This is where I put the business logic. All ok!
Now, I recive using a REST service, through POST an object Company that contains the object Address. I need to save them into the database (MySql).
In the json file there are Company that contains Address!
Until now, I've always done these steps:
Save Address;
Retrieve the Address just saved (i need the idaddress);
I associate the Address to the company using setAddress;
Save Company
I tried to save the object Company received via REST calling the method save from CompanyService (using CompanyRepository) but I got the error:
Column 'idaddress' cannot be null
I ask you. Is there an easier way to save Company and Address at the same time using JpaRepository???
You don't have defined any cascading.
You could define PERSIST to let the Address persist when Company is persisted:
#ManyToOne
#JoinColumn(name = "idaddress", referencedColumnName = "idaddress", nullable = false,
cascade = CascadeType.PERSIST)
public Address getAddress() {
return address;
}
For every method on the EntityManager there is a CascadeType defined.
Read more about the cascade types here:
https://vladmihalcea.com/a-beginners-guide-to-jpa-and-hibernate-cascade-types/

Composite PK with JPA in ORACLE gives ORA-00904 error

I have to map a composite PK with JPA in an Oracle DB.
I've followed other SO questions with relation to this tutorial but I'm still getting the following error:
java.sql.SQLSyntaxErrorException: ORA-00904: "COMPOSITEI0_"."NAME_1": Invalid Identifier (where NAME_1 relates to the name of one of the columns which are part of the PK)
This is my entity (real names not mentioned for data protection reasons):
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#Column(name = "NAME1")
private String name1;
#Column(name = "NAME2")
private String name2;
#Column(name = "NAME3")
private String name3;
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
public CompositePrimaryKeyTableEmbeddable getId() {
return this.id;
}
public void setId(CompositePrimaryKeyTableEmbeddable id) {
this.id = id;
}
// other getters and setters
My #Embeddable id class:
#Embeddable
public class CompositePrimaryKeyTableEmbeddable implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name="name1")
private String name1;
#Column(name="name2")
private String name2;
public CompositePrimaryKeyTableEmbeddable() {
super();
}
public CompositePrimaryKeyTableEmbeddable(String name1, String name2) {
this.name1 = name1;
this.name2 = name2;
}
My #Repository:
#Repository
public interface CompositeIdDao extends JpaRepository<CompositeIdEntity, CompositePrimaryKeyTableEmbeddable> {
}
And finally call to the DB, which only returns null because it's just a test to see if it all works together:
public CompositeIdEto saveCompositeId() {
CompositeIdEntity compositeIdEto = new CompositeIdEntity();
compositeIdEto.setname3("New");
compositeIdEto.setId(new CompositePrimaryKeyTableEmbeddable("ERR", "ER"));
this.compositeIdDao.save(compositeIdEto);
return null;
}
It seems you are duplicating the name1 and name2 columns by declaring them once
in the entity itself and later in the embeddable.
You seem to only need the id embeddable and the name3 declaration in the entity:
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
#Column(name = "NAME3")
private String name3;

change discriminator value at runtime?

I'm working with a hierachy object model with a jpa entity persistance support.
Here the classes model:
User class:
#Entity
#Table(name = "user", catalog = "users")
#NamedQueries({
#NamedQuery(...
})
#Inheritance(strategy= InheritanceType.JOINED)
#DiscriminatorColumn(name = "apType", discriminatorType =
DiscriminatorType.STRING, length = 255)
//#DiscriminatorValue("user")
public class User implements Serializable {
#Transient
protected PropertyChangeSupport changeSupport = new
PropertyChangeSupport(this);
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "apType")
private String apType;
#Basic(optional = false)
#Column(name = "name")
private String name;
public UsuariDeClaus() {
this.setApType("user");
}
public Long getId() {
return id;
}
public void setId(Long id) {
Long oldId = this.id;
this.id = id;
changeSupport.firePropertyChange("id", oldId, id);
}
public String getApType() {
return apType;
}
public void setApType(String apType) {
this.apType = apType;
}
public String getName() {
return name;
}
public void setName(String name) {
String oldName = this.name;
this.name = name;
changeSupport.firePropertyChange("name", oldName, name);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener
listener) {
changeSupport.removePropertyChangeListener(listener);
}
}
ApplicationUser class :
#Entity
#Table(name = "applicationuser", catalog = "usuweb793")
#NamedQueries({
#NamedQuery(...
})
public class ApplicationUser extends Users{
#Basic(optional = false)
#Column(name = "nickname", unique=true)
private String nickname;
#Basic(optional = false)
#Column(name = "password")
private String password;
public ApplicationUser() {
super.setApType("ApplicationUser");
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
String oldPassword = this.password;
this.password = password;
changeSupport.firePropertyChange("password", oldPassword, password);
}
public String getNickname() {
return user;
}
public void setNickname(String nickname) {
String oldNickname = this.nickname;
this.nickname = nickname;
changeSupport.firePropertyChange("nickname", oldNickname, nickname);
}
}
and administratorUser class:
#Entity
#Table(name = "administratoruser", catalog = "usuweb793")
#NamedQueries({
#NamedQuery(...})
public class AdministratorUser extends AplicationUser{
public AdministratorUser() {
super.setApType("administratoruser");
}
}
The entity manager creates on mysql database 4 tables:
sequence, user, aplicationuser and administratoruser.
user table:
id name aptype
1 aaa user
2 bbb aplicationuser
3 ccc administratoruser
aplicationuser table:
id nickname password
2 bbbxxxx bbbyyyyy
3 cccxxxx cccyyyyy
administratoruser table:
id
3
Is possible to change the user priviligies without remove an object and create a new one ?
(i would like the id not to change)
Something like:
User user = em.find(1);
New AplicattionUser(user);
user table:
id name aptype
1 aaa aplicationuser
2 bbb aplicationuser
3 ccc administratoruser
aplicationuser table:
id nickname password
1 aaaxxx aaayyyyy
2 bbbxxxx bbbyyyyy
3 cccxxxx cccyyyyy
administratoruser table:
id
3
According to what I understand and from my POV, if Application and Administrator are just roles for Userthat you can switch between .... remove the inheretence, make a User entity and Role entity -with a corresponding table and join between the two entities with the appropriate join -OneToOne or OneToMany according to to your business case- ..... If you can't change the database/the code ... there is a "dirty" solution (and "dirty" again) that you might try ... make a native bulk update statement to make the change you need but be aware of the following :
1- I am nit sure if it will work, you need to try it
2- You must be sure that the entity is not managed by any persistence context at the time of running
3- You are responsible for refreshing the entity / persistence context/ cache after the update

Path expected for join hibernate

I have a problem with hibernate HQL queries and simple INNER JOIN
String hql = "SELECT NEW es.criteria.crc.model.queryObjects.NameQuery(pf.name) FROM Person as p INNER JOIN PhisicalPerson as pf WHERE pf.idPersona = p.idPersona";
return personService.query(hql);
My Java file has the following code:
public class NameQuery{
private String name;
public NameQuery(String name) {
super();
this.name= name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
}
I recieve the following error in console:
Caused By: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join!
You need to have an association (#OneToMany, #OneToOne) between Person and PhisicalPerson. Having such an association you don't need the where clause
SELECT NEW es.criteria.crc.model.queryObjects.NameQuery(pf.name)
FROM Person as p INNER JOIN p.pf
In the example pf is a property of Person, associated to PhisicalPerson.
class Person {
#OneToOne(mappedBy = "person")
private PhisicalPerson pf;
}
class PhisicalPerson {
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fk_person")
private Person person;
}

could not set a field value by reflection setter

In a spring mvc application using hibernate and MySQL, I am getting an error which seems to indicate that a Name entity cannot find the setter for the id property of the BaseEntity superclass of the Patient entity.
How can I resolve this error?
Here is the error message:
Caused by: org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of myapp.mypackage.Name.patient
Here is the line of code that triggers the error:
ArrayList<Name> names = (ArrayList<Name>) this.clinicService.findNamesByPatientID(patntId);
Here is the BaseEntity, which is the superclass of both Patient and Name:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'BaseEntity' ELSE dtype END)")
public class BaseEntity {
#Transient
private String dtype = this.getClass().getSimpleName();
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
protected Integer id;
public void setId(Integer id) {this.id = id;}
public Integer getId() {return id;}
public void setDtype(String dt){dtype=dt;}
public String getDtype(){return dtype;}
public boolean isNew() {return (this.id == null);}
}
Here is the Patient entity:
#Entity
#Table(name = "patient")
public class Patient extends BaseEntity{
#OneToMany(mappedBy = "patient")
private Set<Name> names;
protected void setNamesInternal(Set<Name> nms) {this.names = nms;}
protected Set<Name> getNamesInternal() {
if (this.names == null) {this.names = new HashSet<Name>();}
return this.names;
}
public List<Name> getNames() {
List<Name> sortedNames = new ArrayList<Name>(getNamesInternal());
PropertyComparator.sort(sortedNames, new MutableSortDefinition("family", true, true));
return Collections.unmodifiableList(sortedNames);
}
public void addName(Name nm) {
getNamesInternal().add(nm);
nm.setPatient(this);
}
//other stuff
}
Here is the Name entity:
#Entity
#Table(name = "name")
public class Name extends BaseEntity{
#ManyToOne
#JoinColumn(name = "patient_id")
private Patient patient;
public Patient getPatient(){return patient;}
public void setPatient(Patient ptnt){patient=ptnt;}
//other stuff
}
The complete stack trace can be viewed at this link.
The SQL generated by Hibernate for the above query is:
select distinct hl7usname0_.id as id1_0_0_, givennames1_.id as id1_45_1_,
hl7usname0_.family as family1_44_0_, hl7usname0_.patient_id as patient3_44_0_,
hl7usname0_.person_id as person4_44_0_, hl7usname0_.suffix as suffix2_44_0_,
hl7usname0_.usecode as usecode5_44_0_, hl7usname0_.codesystem as codesyst6_44_0_,
givennames1_.given as given2_45_1_, givennames1_.name_id as name3_45_1_,
givennames1_.name_id as name3_0_0__, givennames1_.id as id1_45_0__
from hl7_usname hl7usname0_
left outer join hl7_usname_given givennames1_ on hl7usname0_.id=givennames1_.name_id
where hl7usname0_.patient_id=1
When I run this query through the MySQL command line client, it returns the only record in the test database table.
That's not what the stack trace says. The stack trace doesn't say that the ID can't be set. It says:
Caused by: java.lang.IllegalArgumentException: Can not set org.springframework.samples.knowledgemanager.model.HL7Patient field org.springframework.samples.knowledgemanager.model.HL7USName.patient to org.springframework.samples.knowledgemanager.model.HL7USName
So, your HL7USName class has a field named patient of type HL7Patient, and it's impossible to set this field with a value of type HL7USName.
This means that your database contains a Name that has a foreign key to a row of type Name instead of a row of type Patient.

Categories

Resources