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.
Related
I have two models, Owner and Contract. A contract has an instance of an owner, owner does not have a list of contracts. I'm trying to query my list of contracts, to return a list filtered by owner, ie, a list of contracts by owner.
I had tried to follow previous examples and use Criteria to write a custom query, but, following suggestions I've checked the docks and tried to use named queries instead, however, I'm still really struggling.
There was an unexpected error (type=Internal Server Error, status=500).
Named parameter not bound : ownerId; nested exception is org.hibernate.QueryException: Named parameter not bound : ownerId
My models look like this:
#Entity
#Table(name="Contracts")
#NamedQueries({
#NamedQuery(
name = "Contract.allContractsByOwner",
query = "SELECT c FROM Contract c WHERE c.owner.id LIKE :ownerId"
)
})
public class Contract {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private Long id;
#ManyToOne
private Owner owner;
#Column
private double price;
#Column
private String deliverDate;
public Contract(Owner owner, double price, String deliverDate) {
this.id = id;
this.owner = owner;
this.price = price;
this.deliverDate = deliverDate;
}
and
#Entity
#Table(name="Owners")
public class Owner {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private Long id;
#Column
private String name;
public Owner(String name){
this.name = name;
}
my contractRepoImpl
#Service
public class ContractRepositoryImpl implements ContractRepositoryCustom {
ContractRepository contractRepository;
#Autowired
EntityManager entityManager;
public List allContractsByOwner(Long ownerId) {
List contracts = entityManager.createQuery(
"SELECT c FROM Contract c WHERE c.owner.id LIKE :ownerId", Contract.class)
.getResultList();
return contracts;
}
}
which I name in my ContractRepo and ContractRepoCustom files, and then in my controller I map to it like so. But, when I query it in my browser I get the error in my terminal.
#GetMapping(value="/owners/{ownerId}/contracts")
public List allContractsByOwner(#PathVariable("ownerId") Long ownerId){
return contractRepository.allContractsByOwner(ownerId);
}
I appreciate this is probably beginners mistakes, I am trying to follow docs but get a bit stuck with syntax & where annotations need to go.
Thanks JB Nizet, got there in the end
I added parameters to my contractRepoImpl
#Service
public class ContractRepositoryImpl implements ContractRepositoryCustom {
ContractRepository contractRepository;
#Autowired
EntityManager entityManager;
public List allContractsByOwner(Long id) {
List contracts = entityManager.createQuery(
"SELECT c FROM Contract c WHERE c.owner.id = :ownerId", Contract.class)
.setParameter("ownerId", id)
.getResultList();
return contracts;
}
}
that then produced a SQL error, which I fixed by changing my #NamedQuery from 'LIKE' to '=' in my Contract class...
#NamedQueries({
#NamedQuery(
name = "Contract.allContractsByOwner",
query = "SELECT c FROM Contract c WHERE c.owner.id = :ownerId"
)
})
I have a enum of few status value
NEW, REVIEWD, PUBLISHED, PENDING, UPDATED, SPAM, DUPLICATE, IRRELEVANT, UNPUBLISHED
I don't want to use them as enumerated so created one entity for that. For convenient I want to keep a column in entity to initialize status from enum and convert that enumerated value to a Object of status entity. for this..
I have two entity. I want to refer a column with value from another entity.
Basically I want to initialize a object with formula.
Entities are
#Entity
#Table(name = "event_status")
public class EventStatus {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="eventStatusId")
private Integer eventStatusId;
#Enumerated(EnumType.STRING)
#Column(unique = true,name="eventStatusType")
private EventStatusType eventStatusType;
public EventStatus() {
this(EventStatusType.NEW);
}
public EventStatus(EventStatusType eventStatusType) {
super();
this.eventStatusType = eventStatusType;
}
public Integer getEventStatusId() {
return eventStatusId;
}
public EventStatusType getEventStatusType() {
return eventStatusType;
}
public void setEventStatusId(Integer eventStatusId) {
this.eventStatusId = eventStatusId;
}
public void setEventStatusType(EventStatusType eventStatusType) {
this.eventStatusType = eventStatusType;
}
}
I have another entity in which I am referring object of this entity
#Entity
#Table(name = "event_")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Event implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id_")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Transient
public EventStatusType eventStatusType = EventStatusType.NEW;
#ManyToOne(fetch = FetchType.EAGER, targetEntity = EventStatus.class)
#Formula("select * from event_status where eventStatusId= 1")
private EventStatus status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public EventStatus getStatus() {
System.out.println("Event.getStatus() " + status);
return status;
}
public void setStatus(EventStatus status) {
System.out.println("Event.setStatus()");
this.status = status;
}
}
This is not giving any exception but not initializing this value.
Is it possible to initialize this EntityStatus with value of eventStatusType in Event entity
I would like to explain that based on the documentation:
5.1.4.1.5. Formula
Sometimes, you want the Database to do some computation for you rather than in the JVM, you might also create some kind of virtual column. You can use a SQL fragment (aka formula) instead of mapping a property into a column. This kind of property is read only (its value is calculated by your formula fragment).
#Formula("obj_length * obj_height * obj_width")
public long getObjectVolume()
The SQL fragment can be as complex as you want and even include subselects.
...
5.1.7.1. Using a foreign key or an association table
...
Note
You can use a SQL fragment to simulate a physical join column using the #JoinColumnOrFormula / #JoinColumnOrformulas annotations (just like you can use a SQL fragment to simulate a property column via the #Formula annotation).
#Entity
public class Ticket implements Serializable {
#ManyToOne
#JoinColumnOrFormula(formula="(firstname + ' ' + lastname)")
public Person getOwner() {
return person;
}
...
}
Also, we should use insertable = false, updatable = false, because such mapping is not editable
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.
I'm using JPA/EclipseLink, it throws this exception
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
Unknown column 'NAME' in 'field list'
Below is the generated query:
Call: SELECT id, DTYPE, fullname, NAME, code FROM PERSON WHERE
((accountId = ?) AND (DTYPE = ?)) bind => [1, Employee]
in which
#Entity
#Table(name = "PERSON")
public class Person
implements Serializable {
....
#Column(name = "fullname", nullable = false)
public String getFullName() {
return this.fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
....
}
#Entity
#Table(name="EMPLOYEE")
#PrimaryKeyJoinColumn(name="personId")
public class Employee
extends Person
implements Serializable {
....
#Column(name="code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
I don't have the NAME column on neither PERSON table nor EMPLOYEE table, why does it casually add that column to the query and cause the problem for itself (and for me)?
--- EDITED -----
I don't have any name property or member or something similar to that word in either PERSON nor EMPLOYEE entity.
NAME looks like it is defaulting (since you seem to set the field names as lower case), so check for a getName/setName methods in the Person class. Are you using an orm.xml file?
If you still cannot find the problem, turn EclipseLink logging to Finest:
and check the log during predeployment/deployment stages. The EclipseLink processing for the Person and Employee classes should show why it is determining there should be a NAME field.
I have following kinds of classes for hibernate entity hierarchy. I am trying to have two concrete sub classes Sub1Class and Sub2Class. They are separated by a discriminator column (field) that is defined in MappedSuperClass. There is a abstract entity class EntitySuperClass which is referenced by other entities. The other entities should not care if they are actually referencing Sub1Class or Sub2Class.
It this actually possible? Currently I get this error (because column definition is inherited twice in Sub1Class and in EntitySuperClass) :
Repeated column in mapping for entity: my.package.Sub1Class column: field (should be mapped with insert="false" update="false")
If I add #MappedSuperClass to EntitySuperClass, then I get assertion error from hiberante: it does not like if a class is both Entity and a mapped super class. If I remove #Entity from EntitySuperClass, the class is no longer entity and can't be referenced from other entities:
MappedSuperClass is a part of external package, so if possible it should not be changed.
My classes:
#MappedSuperclass
public class MappedSuperClass {
private static final String ID_SEQ = "dummy_id_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = ID_SEQ)
#GenericGenerator(name=ID_SEQ, strategy="sequence")
#Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false)
private Integer id;
#Column(name="field", nullable=false, length=8)
private String field;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
#Entity
#Table(name = "ACTOR")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="field", discriminatorType=DiscriminatorType.STRING)
abstract public class EntitySuperClass extends MappedSuperClass {
#Column(name="description", nullable=false, length=8)
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
#Entity
#DiscriminatorValue("sub1")
public class Sub1Class extends EntitySuperClass {
}
#Entity
#DiscriminatorValue("sub2")
public class Sub2Class extends EntitySuperClass {
}
#Entity
public class ReferencingEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
#Column
private Integer value;
#ManyToOne
private EntitySuperClass entitySuperClass;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public EntitySuperClass getEntitySuperClass() {
return entitySuperClass;
}
public void setEntitySuperClass(EntitySuperClass entitySuperClass) {
this.entitySuperClass = entitySuperClass;
}
}
In my project it is done this way:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "field", discriminatorType = DiscriminatorType.STRING)
#DiscriminatorValue("dummy")
public class EntitySuperClass {
// here definitions go
// but don't define discriminator column here
}
#Entity
#DiscriminatorValue(value="sub1")
public class Sub1Class extends EntitySuperClass {
// here definitions go
}
And it works. I think your problem is that you needlessly define discriminator field in your superclass definition. Remove it and it will work.
In order to use a discriminator column as a normal property you should make this property read-only with insertable = false, updatable = false. Since you can't change MappedSuperClass, you need to use #AttributeOverride:
#Entity
#Table(name = "ACTOR")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="field", discriminatorType=DiscriminatorType.STRING)
#AttributeOverride(name = "field",
column = #Column(name="field", nullable=false, length=8,
insertable = false, updatable = false))
abstract public class EntitySuperClass extends MappedSuperClass {
...
}
You can map a database column only once as read-write field (a field that has insertable=true and/or updatable=true) and any number times as read-only field (insertable=false and updatable=false). Using a column as #DiscriminatorColumn counts as read-write mapping, so you can't have additional read-write mappings.
Hibernate will set value specified in #DiscriminatorColumn behind the scenes based on the concrete class instance. If you could change that field, it would allow modifying the #DiscriminatorColumn field so that your subclass and value in the field may not match.
One fundamental: You effectively should not need to retrieve your discriminator column from DB. You should already have that information within the code, of which you use in your #DiscriminatorValue tags. If you need read that from DB, reconsider carefully the way you are assigning discriminators.
If you need it in final entity object, one good practice can be to implement an Enum from discriminator value and return store it in a #Transient field:
#Entity
#Table(name="tablename")
#DiscriminatorValue(Discriminators.SubOne.getDisc())
public class SubClassOneEntity extends SuperClassEntity {
...
#Transient
private Discriminators discriminator;
// Setter and Getter
...
}
public enum Discriminators {
SubOne ("Sub1"),
SubOne ("Sub2");
private String disc;
private Discriminators(String disc) { this.disc = disc; }
public String getDisc() { return this.disc; }
}