I am a beginner and I am doing some inheritance exercises in hibernate. I have two classes, a superclass and a subclass, both are joined by inheritance SINGLE_TABLE.
The problem is that when I want to persist an object of the subclass to the database, hibernate tries to make an "INSERT" in the table of the superclass. And this produces the error "unknown column "color "in 'field list'", since the "color" column does not exist in the table of the superclass.
I have not mapped associations between both tables. Should I do that? My textbooks do not specify it. Otherwise, what should I do?
SUPERCLASS: --------------------------------------------------------------------
#Entity
#Table(name="autos")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
name = "pe_discriminador",
discriminatorType = DiscriminatorType.STRING)
#DiscriminatorValue(value = "a1")
public class auto implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="marca")
private String marca;
#Column(name="modelo")
private String modelo;
public auto(){
}
public auto(int id, String marca, String modelo) {
this.id = id;
this.marca = marca;
this.modelo = modelo;
}
public long getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMarca() {
return marca;
}
public void setMarca(String marca) {
this.marca = marca;
}
public String getModelo() {
return modelo;
}
public void setModelo(String modelo) {
this.modelo = modelo;
}
#Override
public String toString() {
return "auto{" + "id=" + id + ", marca=" + marca + ", modelo=" + modelo + '}';
}
}
SUBCLASS ----------------------------------------------------------------------
#Entity
#Table(name="autos")
#DiscriminatorValue("a2")
public class auto2 extends auto{
int id2;
public auto2() {
}
public auto2(int id2, String color, double motor, int id, String marca, String modelo) {
this.id2=id2;
this.color=color;
this.motor=motor;
setMarca(marca);
setModelo(modelo);
}
#Column(name="color")
private String color;
#Column(name="motor")
private double motor;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getMotor() {
return motor;
}
public void setMotor(double motor) {
this.motor = motor;
}
#Override
public String toString() {
return "auto2{" + ", color=" + color + ", motor=" + motor + '}';
}
}
HIBERNATE ERROR LOG:----------------------------------------------------------
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
oct 21, 2018 10:22:51 AM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
oct 21, 2018 10:22:52 AM org.hibernate.cfg.AnnotationBinder bindClass
WARN: HHH000139: Illegal use of #Table in a subclass of a SINGLE_TABLE hierarchy: entidades.auto2
Hibernate: insert into autos (marca, modelo, color, id2, motor, pe_discriminador) values (?, ?, ?, ?, ?, 'a2')
oct 21, 2018 10:22:54 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1054, SQLState: 42S22
oct 21, 2018 10:22:54 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Unknown column 'color' in 'field list'
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3072)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3663)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:359)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:292)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:200)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:131)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:709)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:701)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:696)
at testeo.TestAuto.main(TestAuto.java:225)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'color' in 'field list'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.Util.getInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:944)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3978)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3914)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2530)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2495)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1903)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2124)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2058)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5158)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2043)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
... 22 more
0) Prequel to Answer
Before we jump into the answer, I would like to point out something: The example code looks a bit messy. For example the indentation could be more intuitive and typically classes are named in PascalCase (that is camelCase with a capital first letter). Many style guides are out there that can help you (e.g. by Google). Believe me: It makes coding more fun!
1) Actual Answer
There are multiple strategies to save class hierarchies with hibernate:
Single table: All classes in the hierarchy are persisted into one table (with potentially many columns)
Table per class: Each concrete class is persisted into its own table
Joined: Each concrete class as well as the super class are persisted into a table each
You chose a SINGLE_TABLE inheritance strategy. That means, all classes and sub-classes that belong to this hierarchy will be persisted into one table (table per class hierarchy).
From your description of the error, it seems that your database schema, fits a different strategy.
a) Table per class strategy
If you have, one table per concrete subclass (that means: no table for the abstract super class), try:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Auto {
b) Join strategy
If the abstract superclass and your concrete subclasses each have a table, then go with:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Auto{
#Id
private int id;
// getters, setters, ...
}
#Entity
#PrimaryKeyJoinColumn(name = "id")
public class RaceAuto extends Auto {
// ...
}
In both cases, you will not need a discriminator column. The Hibernate documentation can be misleading if you want to use annotations. I found this blog post quite helpful.
Related
Hi I'm trying to make output of annual salary using below function:
List results=session.createQuery("select comp.annual_sales from employee").list();
My tables are defined as below
#Entity(name="company")
#Table(name="company")
public class company{
#Id
#Column(name="company_id")
private int company_id;
#Column(name="company_name")
private String company_name;
#Column(name="annual_sales")
private double annual_sales;
#Column(name="founding_date")
#Temporal(TemporalType.DATE)
private Date founding_date;
/*#OneToMany(mappedBy = "comp", cascade = CascadeType.ALL, orphanRemoval = true)
private List<employee> emps; //= new HashSet<employee>();*/
public company(){}
public company(int company_id, String company_name, double annual_sales, Date founding_date){
this.company_id=company_id;
this.company_name=company_name;
this.annual_sales=annual_sales;
this.founding_date=founding_date;
}
}
#Entity(name="employee")
#Table(name="employee")
public class employee{
#Id
#Column(name="employee_id")
private int employee_id;
#Column(name="first_name")
private String first_name;
#Column(name = "last_name")
private String last_name;
#Column(name="salary")
private int salary;
#Column(name="company")
private int company;
#ManyToOne
#JoinColumn(name="comp")
private company comp;
/*#OneToMany(mappedBy = "emp", cascade = CascadeType.ALL, orphanRemoval = true)
private List<account> accs; //= new HashSet<account>();*/
public employee(){}
public employee(int employee_id, String first_name, String last_name, int salary, int company){
this.employee_id=employee_id;
this.first_name=first_name;
this.last_name=last_name;
this.salary=salary;
this.company=company;
}
}
#Entity(name="account")
#Table(name="account")
public class account{
#Id
#Column(name="account_id")
private int account_id;
#Column(name="bank_name")
private String bank_name;
#Column(name="opening_date")
#Temporal(TemporalType.DATE)
private Date opening_date;
#Column(name="owner")
private int owner;
#ManyToOne
#JoinColumn(name="emp")
private employee emp;
public account(){}
public account(int account_id, String bank_name, Date opening_date, int owner){
this.account_id=account_id;
this.bank_name=bank_name;
this.opening_date=opening_date;
this.owner=owner;
}
}
and the following error comes out:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1054, SQLState: 42S22
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Unknown column 'employee0_.comp' in 'where clause'
I have three major question here:
I have no column or attribute named 'employee0_' and why is it appearing in the error?
I have no 'where clause' sql function but why is such error appearing?
I've looked through many questions but it seemed nobody has similar problem with me nor they could solve my problem. The closest thing I could find was this: ERROR: Unknown column 'user0_.id' in 'field list'
but adding #OnetoMany clause did not solve my problem.
How should I fix this error?
employee0_ is just an alias, that's used by Hibernate in the query. The error itself refers to the column comp, which Hibernate cannot find in the employee table. The where clause is added, because Hibernate needs to load the company entity, which is referred to in the employee entity.
So to fix the error, you should make sure that you actually have a column named comp in the employee table, and if not, either use the correct name in the annotation or create the column.
I feel like this is answered 100 times. but for some reason, I've tried every single answer and none of them fix my problem.
I have a simple Parent with a simple primary key.
It has a list of children. The foreign key is part of the child's composite primary key.
The Db is postgresql.
Parent class
#Entity
#Table(name = "person")
class Person {
#Id
#GeneratedValue(generator = "person_id_seq")
#Column(name = "person_id")
private Long personId;
#OneToMany(mappedBy="person", cascade = CascadeType.ALL)
private List<PersonIdentifier> personIdentifiers = new ArrayList<>();
public void addPersonIdentifier(PersonIdentifier pi) {
this.personIdentifiers.add(pi);
pi.setPerson(this);
}
// other columns and getters / setters left out for brevity
}
Child class w/pk class
#Entity
#Table(name = "person_identifier")
#IdClass(PersonIdentifierPK.class)
public class PersonIdentifier {
#Id
#Column(name="person_id")
private Long personId;
#Id
#Column(name="person_identifier")
private String personIdentifier;
#Id
#Column(name="person_identifier_type")
private String personIdentifierType;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="person_id", insertable=false, updatable=false)
private Person person;
// other columns and getters / setters left out for brevity
}
public class PersonIdentifierPK {
#Column(name = "person_id")
private Long personId;
#Column(name = "person_identifier")
private String personIdentifier;
#Column(name = "person_identifier_type")
private String personIdentifierType;
// getters/setters left out
#Override
public int hashCode() {
// implementation
}
#Override
public boolean equals(Object obj) {
// implementation
}
}
USAGE:
Patient p = new Patient();
PersonIdentifier pi = new PersonIdentifier();
pi.setPersonIdentifierType("NAME");
pi.setPersonIdentifier("John Doe");
p.addPersonIdentifier(pi);
personRepository.save(p);
TransactionManager
public static <T> T getRepository(Class<T> repositoryInterface, Project project) {
if (entityManager == null) {
DataSource ds = ConnectionPools.getStagingDB();
emFactory = entityManagerFactory(ds, hibernateProperties(project.getStagingDbJdbcUrl(), project.getStagingDbUserName(), project.getStagingDbPassword()));
EntityManagerCreator creator = new EntityManagerCreator();
entityManager = creator.create(emFactory);
}
final JpaTransactionManager xactManager = new JpaTransactionManager(emFactory);
JpaRepositoryFactory factory = new JpaRepositoryFactory(entityManager);
factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
#Override
public void postProcess(ProxyFactory factory, RepositoryInformation info) {
factory.addAdvice(new TransactionInterceptor(xactManager, new MatchAlwaysTransactionAttributeSource()));
}
});
return factory.getRepository(repositoryInterface);
}
if i remove the cascade=CascadeType.ALL then i end up with a new person in my person database with a properly generated Id, but the person_identifier table is still empty obviously.
however, with the cascading, it fails to commit anything due to the personIdentifier's "person_id" column trying to be set to null.
my understanding is with the mapping, and the join column, and setting the parent on the child, that this column will get set automatically to whatever it is on the parent?
the spring sql output looks like this (there are more columns in parent table i just removed them for privacy reasons):
select nextval ('person_id_seq')
insert into person (person_id) values (?)
binding parameter [1] as [BIGINT] - [70]
insert into person_identifier (active, create_date, modified_date, person_id, person_identifier, person_identifier_type) values (?, ?, ?, ?, ?, ?)
binding parameter [1] as [BOOLEAN] - [true]
binding parameter [2] as [TIMESTAMP] - [Thu Sep 19 12:34:52 EDT 2019]
binding parameter [3] as [TIMESTAMP] - [null]
binding parameter [4] as [BIGINT] - [null]
binding parameter [5] as [VARCHAR] - [John Doe]
binding parameter [6] as [VARCHAR] - [NAME]
you can see where it passed null into person_id of person_identifier insert, even though it passed 70 into the person tables insert statement.
this obviously leads to
ERROR: null value in column "person_id" violates not-null constraint
I've tried refactoring the code a multitude of ways. Using embeddedId, removing mappedBy and using joincolumn on the parent instead. etc etc.
I am trying to create a project that will use Hibernate to store the objects to the database.
If I simply insert (save) an object that does not contain a mapping with another table everything works fine. However, I have a case where there is a connection between three tables. The tables are the Asset, MonetaryValue and CurrencyType (see below).
When an Asset is inserted, the monetaryValueType must be provided (by the user ) along with the currency type. Asset holds a OneToOne relation with the MonetaryValueType and MonetaryValueType holds a OneToOne relation to the CurrencyType Table.
More specifically, below you will find the database tables.
Asset(asset_id,ownerIID,valueID,samID), where valueID is the foreign key to the MonetaryValueType Table (OneToOne undirectional mapping)
MonetaryValueType(mvID, mValue,currencyId), where currencyID is the foreign key to the CurrencyType Table (OneToOne undirectional mapping)
CurrencyType(currencyID,currField,currValue,currSymbol).
The problem is that every time I create the asset object and I am calling the asset service to save the element, Hibernate either create a select query that tries to select from a database table I did never define or Inserts in the currency field with wrong column names (i.e. currency_field instead of currField etc.)
I've tried to play with all the Cascade types but nothing seems to work.
Asset.java
#Entity
#Table(name="asset")
public class Asset implements java.io.Serializable{
#Id
#Column(name="assetID", unique = true, nullable = false)
private long assetID;
#Column(name="ownerID")
private long ownerID;
#OneToOne
#JoinColumn(name="valueID")
private MonetaryValueType monetaryValueType;
#Column(name="samID")
private long samID;
------------Constructor, Getters , Setters-----
MonetaryValueType.java
#Entity
#Table(name="monetaryvaluetype")
public class MonetaryValueType{
#Id
#Column(name="mvID",nullable = false,unique = true)
private Long id;
#Column(name="mValue")
private double mValue;
#OneToOne
#JoinColumn(name="currencyId")
private CurrencyType currency;
------------Constructor, Getters , Setters-----
CurrencyType.java
#Entity
#Table(name="currencytype")
public class CurrencyType implements java.io.Serializable {
#Id
#Column(name="currencyID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int currencyID;
#Column(name="currField")
private String currField;
#Column(name="currValue")
private String currValue;
#Column(name="currSymbol")
private String currSymbol;
------------Constructor, Getters , Setters-----
Every entity holds its own DAO,DAOImpl, Service and ServiceImpl class. For instance, for the asset class the DAOImpl and ServiceImpl can be found below:
AssetDAOImpl.java
#Repository
public class AssetDAOImpl implements AssetDAO{
private Logger logger = LoggerFactory.getLogger(this.getClass());
//entity manager field
#Autowired
private EntityManager entityManager;
#Override
public List<Asset> findAll() {
Session currentSession = entityManager.unwrap(Session.class);
//create a query
Query theQuery =
currentSession.createQuery("from asset",Asset.class);
//execute query and get result list
List<Asset> aModelElements = theQuery.getResultList();
//return the results
return aModelElements;
}
#Override
public Asset findById(int theId) {
return null;
}
#Override
public Asset insert(Asset assetElement) {
//Session currentSession = entityManager.unwrap(Session.class);
boolean success = false;
try {
entityManager.persist(assetElement);
logger.info("Asset -> {}", assetElement);
return assetElement;
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
AssetServiceImpl.java
#Service
public class AssetServiceImpl implements AssetService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private AssetDAO assetDAO;
#Autowired
public AssetServiceImpl(AssetDAO theAssetDAO){
assetDAO=theAssetDAO;
}
#Override
#Transactional
public List<Asset> findAll() {
return assetDAO.findAll();
}
#Override
#Transactional
public Asset findById(int theId) {
return assetDAO.findById(theId);
}
#Override
#Transactional
public Asset insert(Asset theAsset) {
assetDAO.insert(theAsset);
return theAsset;
}
...
The class that I use to fill the asset class (and all its children) is:
UniqueIDGenerator uniqueIDGenerator = new UniqueIDGenerator();
CurrencyType currencyType = new CurrencyType();
Asset asset = new Asset();
MonetaryValueType monetaryValueType = new MonetaryValueType();
currencyType.setCurrValue(ctx.value().monetaryValueType().currency().CurrencyType().getText());
currencyType.setCurrSymbol("currency");
monetaryValueType.setId(uniqueIDGenerator.nextId());
monetaryValueType.setmValue(Double.parseDouble(ctx.value().monetaryValueType().mValue().getText()));
monetaryValueType.setCurrency(currencyType);
asset.setMonetaryValueType(monetaryValueType);
asset.setAssetID(uniqueIDGenerator.nextId());
asset.setOwner(uniqueIDGenerator.nextId());
asset.setSamID(uniqueIDGenerator.nextId());
assetService.insert(asset);
Whenever I call the class mentioned above, I get the following error:
Hibernate:
insert
into
element1
(datefrom, dateto, description, name, statusid, samid)
values
(?, ?, ?, ?, ?, ?)
2019-08-05 20:19:00 INFO MyClass:63 - the result is:true
Hibernate:
select
monetaryva_.mvid,
monetaryva_.currency_id as currency3_57_,
monetaryva_.m_value as m_value2_57_
from
monetaryvaluetype monetaryva_
where
monetaryva_.mvid=?
2019-08-05 20:19:01.084 WARN 56712 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1054, SQLState: 42S22
2019-08-05 20:19:01.084 ERROR 56712 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : Unknown column 'monetaryva_.currency_id' in 'field list'
As you can see, hibernate created columns (currency_id instead of currencyID) that are not in accordance with my database tables even though I used the #Column annotation.
Use following two lines in your application.properties file
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
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.
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.