I have 2 java classes, one of them contains the other as a list by #ElementCollection.
When I try to set that list, following error occurs:
Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.1.3.v20110304-r9073): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
Error Code: 942
Call: SELECT t0.VERSIONS FROM MainProcess_VERSIONS t0 WHERE (t0.MainProcess_SUBJECT_ID = ?)
bind => [#id]
Query: DirectReadQuery(name="versions" sql="SELECT t0.VERSIONS
FROM MainProcess_VERSIONS t0 WHERE (t0.MainProcess_SUBJECT_ID = ?)")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:333)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:683)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:526)
.
.
.
at ...Editor.MAINPROCESS._persistence_propertyChange(MAINPROCESS.java)
at ...Editor.MAINPROCESS._persistence_set_versions(MAINPROCESS.java)
at ...MAINPROCESS.setVersions(MAINPROCESS.java:79)
at ...DataModel.fillSubprocessSubject(DataModel.java:643)
at ...DataModel.load(DataModel.java:321)
If I remove the #ElementCollection then I get the following error
Error Code: 942
Call:
SELECT t1.ACT_VERSION, t1.SUBJECT_ID, t1.ACT_VERSION_REMARK,
t1.ACT_VALID_TO, t1.ACT_VERSION_ACCEPTED, t1.NORMALRETURNVALUES, t1.ACT_VALID_FROM
FROM MAINPROCESS_MAINPROCESSVERSION t0, MAINPROCESSVERSION t1
WHERE ((t0.MainProcess_SUBJECT_ID = ?) AND ((t1.SUBJECT_ID = t0.SUBJECT_ID)
AND (t1.ACT_VERSION = t0.ACT_VERSION)))
bind => [#id]
Here are my classes,
MainProcess:
#Entity
public class MainProcess implements Serializable {
#Id
#Column(name = "SUBJECT_ID", nullable = false)
private Long subjectId;
...other columns
#ElementCollection
private List<MainProcessVersion> versions = new ArrayList<MainProcessVersion>();
public MainProcess() {
}
public void setVersions(List<MainProcessVersion> versions) {
this.versions = versions;
}
public List<MainProcessVersion> getVersions() {
return versions;
}
other getters and setters...
}
MainProcessVersion:
#Entity
#IdClass(MainProcessVersionPK.class)
public class MainProcessVersion implements Serializable {
#Id
#Column(name = "SUBJECT_ID", nullable = false)
#XmlTransient
private Long subjectId;
#Id
#Column(name = "ACT_VERSION")
private Long actVersion;
...other columns
private List<String> normalReturnValues;
public MainProcessVersion() {
}
getters and setters...
}
And the function in which the error occurs:
private MainProcess fillSubprocessSubject(Long Id) {
MainProcess p = someFacade.getProcess(Id);
List<MainProcessVersion> versions = someFacade.getProcessVersions(Id);
p.setVersions(versions); //error is here
return p;
}
Thanks in advance for any help.
I managed to solve my problem. Most important was to understand the difference between #ElementCollection and #OneToMany annotation. I cannot better explain like this.
So the problem was that my MainProcessVersion.java was annotated with #Entity, thus I could not add the #ElementCollection annotation to it in the MainProcess.java.
#ElementCollection //One cannot use this annotation because MainProcessVersion is an entity.
private List<MainProcessVersion> versions = new ArrayList<MainProcessVersion>();
But I need the Entity, so I created resultRow class wich is the same as my Entity class except the annotation. After query selection, I cast my result to my new resultRow class and I can set that list in the MainProcess.java.
My resultRow class:
public class MainProcessVersionResultRow implements Serializable {
private Long subjectId;
...other code
}
My old MainProcess class
#Entity
public class MainProcess implements Serializable {
#Id
#Column(name = "SUBJECT_ID", nullable = false)
private Long subjectId;
...other columns
//without #ElementCollection and the new resultRow object type
private List<MainProcessVersionResultRow> versions = new ArrayList<MainProcessVersionResultRow>();
public MainProcess() {
}
...getters. setters
}
And then, I "cast" my entity to resultRow class:
private MainProcess fillSubprocessSubject(Long subjectId) {
MainProcess p =
someFacade.getSubprocessSubject(subjectId);
List<MainProcessVersion> versions = someFacade.getProcessVersions(subjectId);
List<MainProcessVersionResultRow> versionResultRows = new ArrayList<MainProcessVersionResultRow>();
for (MainProcessVersion vs : versions) {
MainProcessVersionResultRow versionSingleResultRow = new MainProcessVersionResultRow(vs);
versionSingleResultRow.setNormalReturnValues(processReturnValues(p.getSubjectId(), vs.getActVersion()));
versionResultRows.add(versionSingleResultRow);
}
p.setVersions(versionResultRows); //does not throw an error any more
return p;
}
So conclusion:
Do not use #ElementCollection on a class that has an #Entity annotation.
Related
i use querydsl, hibernate
i want select data by Dto in Dto list but not working
here is my code
#Data
#Entity
public class Team {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
#Entity
#Setter
public class Member {
#Id
#GeneratedValue
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "team_id")
private Team team;
}
#Setter
public class TeamDto {
private Long id;
private String name;
private List<MemberDto> members = new ArrayList<>();
}
#Setter
public class MemberDto {
private Long id;
private String name;
}
test
#BeforeEach
void setup() {
queryFactory = new JPAQueryFactory(em);
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member("memberA");
member.setTeam(team);
em.persist(member);
Member member2 = new Member("memberB");
member2.setTeam(team);
em.persist(member2);
em.flush();
em.clear();
}
#Test
void t1() {
TeamDto teamDto = queryFactory
.select(Projections.fields(
TeamDto.class,
team.id,
team.name,
Projections.fields(
MemberDto.class,
member.id,
member.name
).as("members")
))
.from(team)
.fetchOne();
System.out.println("teamDto = " + teamDto);
}
error log is = java.lang.IllegalArgumentException: com.blog.querydsltest.domain.dto.MemberDto is not compatible with java.util.List
what is problem?? is impossible bring data by List dto??
i try to change Projections.fields to bean, construct, ... but not working
how can i do ?
Multi level aggregations are currently not supported by QueryDSL. There are also no concrete plans to support it as of now.
For a DTO solution that can fetch associations with it, I recommend you to have a look at Blaze-Persistence Entity Views. With Entity Views the code for your DTO would look something like the following:
#EntityView(Team.class)
public interface TeamDto {
#IdMapping public Long getId();
#Mapping("name") public String getName();
#Mapping("members") public List<MemberDTO> getMembers();
}
If members is not an association on your TeamEntity, you can map it through a #MappingCorrelated binding.
Disclaimer: I am a contributor for Hibernate, QueryDSL and Blaze-Persistence.
I have the following 3 Hibernate Entities within my Java Project:
CompanyStatus
#Entity(name = "company_status")
#Table(name = "company_status")
public class CompanyStatus implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JsonProperty
#Column(name = "company_status_id")
private Integer companyStatusId;
#JsonProperty
#Column(name = "company_status_label")
private String companyStatusLabel;
}
Employee Status
#Entity(name = "employee_status")
#Table(name = "employee_status")
public class EmployeeStatus implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonProperty
#Column(name = "employee_status_id")
private Integer employeeStatusId;
#JsonProperty
#Column(name = "employee_status_name")
private String employeeStatusName;
// many other fields
}
CompanyStatusEmployeeStatus (Entity linking the 2 entities- one to one relationship)
#Entity(name = "company_status_employee_status")
#Table(name = "company_status_employee_status")
public class CompanyStatusEmployeeStatus implements Serializable {
// int(20)
#Id
#JsonProperty
#Column(name = "company_status_id")
private Integer companyStatusId;
// int(20)
#JsonProperty
#Column(name = "employee_status_id")
private Integer employeeStatusId;
}
I only want to return the necessary fields in my JSON response to the front end , so In order to do so I have created a smaller CompanyStatusDTO object that also has an EmployeeStatusDTO list nested
CompanyStatusDTO
public class CompanyStatusDTO {
#JsonProperty
private Integer companyStatusId;
#JsonProperty
private String companyStatusLabel;
#JsonProperty
private List <EmployeeStatusDTO> employeeStatusDTOs;
}
EmployeeStatusDTO
public class EmployeeStatusDTO {
#JsonProperty
private Integer employeeStatusId;
#JsonProperty
private String employeeStatusName;
}
However, I am relatively new to using Hibernate - is there a way that I can create a query that will map results directly from my MySQL DB to my CompanyStatusDTOobject?
If so, how can do I this?
you can directly map query result to you desired DTO using NativeQuery (datatype must match)
String q = "select ... from table"; // your sql query
Query query = getEntityManager().createNativeQuery(q, "EmployeeStatusDTO");
EmployeeStatusDTO data = (EmployeeStatusDTO) query.getSingleResult();
return data;
This is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
If you adapt the CompanyStatus and CompanyStatusEmployeeStatus entities a bit and add the following:
public class CompanyStatus implements Serializable {
//...
#OneToMany(mappedBy = "companyStatus")
private Set<CompanyStatusEmployeeStatus> employeeStatuses;
}
public class CompanyStatusEmployeeStatus implements Serializable {
//...
#JsonProperty
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "company_status_id", insertable = false, updatable = false)
private CompanyStatus companyStatus;
#JsonProperty
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "employee_status_id", insertable = false, updatable = false)
private EmployeeStatus employeeStatus;
}
Your model could look like the following:
#EntityView(CompanyStatus.class)
public interface CompanyStatusDTO {
#IdMapping
Integer getCompanyStatusId();
String getCompanyStatusLabel();
#Mapping("employeeStatuses.employeeStatus")
List<EmployeeStatusDTO> getEmployeeStatusDTOs();
}
#EntityView(EmployeeStatus.class)
public interface EmployeeStatusDTO {
#IdMapping
Integer getEmployeeStatusId();
String getEmployeeStatusName();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
CompanyStatusDTO c = entityViewManager.find(entityManager, CompanyStatusDTO.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
You can try this:
public class Dao{
private SessionFactory sessionFactory;
public Dao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public <T> T save(final T o){
return (T) sessionFactory.getCurrentSession().save(o);
}
public void delete(final Object object){
sessionFactory.getCurrentSession().delete(object);
}
public <T> T get(final Class<T> type, final Long id){
return (T) sessionFactory.getCurrentSession().get(type, id);
}
public <T> List<T> getAll(final Class<T> type) {
final Session session = sessionFactory.getCurrentSession();
final Criteria crit = session.createCriteria(type);
return crit.list();
}
// and so on, you should get the idea
and you can then access like so in the service layer:
private Dao dao;
#Transactional(readOnly = true)
public List<MyEntity> getAll() {
return dao.getAll(MyEntity.class);
}
(column and variable name changed after posting question)i am writing join query using entityManager.createNativeQuery(somequery) in jpa custom method when i run code i get following error :
com.ibm.db2.jcc.am.SqlException: [jcc][10150][10300][4.12.56] Invalid >parameter: Unknown column name exc_seq_nbr. ERRORCODE=-4460, SQLSTATE=null
i am using IBM DB2 server and spring boot
exceptionTenderPK (object in entity class) is not being mapped correctly thats why getting invalid column can someone please tell me how to map exceptionTenderPK object class
Note: i cant use #OneToMany in this case because tables are unrelated
#Entity
#Table(name = "Table_name")
#Data
public class MainPojoclass {
#EmbeddedId
#JsonProperty(value = "mainPojoclassPK")
private MainPojoclassPK mainPojoclassPK;
#Column(name = "amt")
#JsonProperty(value = "amt")
private BigDecimal amt;
#Column(name = "tndid")
#JsonProperty(value = "tndid")
private String tndid;
#Column(name = "cde")
#JsonProperty(value = "cde")
private String cde;
#Column(name = "ind")
#JsonProperty(value = "ind")
private String ind;
#Column(name = "user")
#JsonProperty(value = "user")
private String user;
#Column(name = "updatedtime")
#JsonProperty(value = "updatedtime")
private Date updatedtime;
#Column(name = "src")
#JsonProperty(value = "src")
private String src;
#Column(name = "stat")
#JsonProperty(value = "stat")
private String stat;
}
#Transactional
public interface JoinQueryRepository extends JpaRepository<MainPojoclass, Long>, JoinQueryRepositoryCustom{
}
public interface JoinQueryRepositoryCustom {
List<MainPojoclass> getGRDetails(MainPojoclass et,Date reportDate);
}
public class JoinQueryRepositoryImpl implements JoinQueryRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#SuppressWarnings("all")
#Override
public List<MainPojoclass> getGRDetails(MainPojoclass et,Date rdate) {
String queryStr = "select et.Salss_DTE from table et"
+ " join dte etr on et.Salss_DTE = etr.Salss_DTE where et.nbr =? ";
List<MainPojoclass> datalist = null;
Query query = entityManager.
createNativeQuery(queryStr,"mapping")
.setParameter(1, 222);
datalist = query.getResultList();
return datalist;
}
}
The error says that there is no column exc_seq_nbr and you used that in your EntityResult mapping.
In your query you only return et.SLS_DTE you have to return all columns that are in the result set mapping.
Hi all since i am not getting any solutions i am going with below solution it works for me and removing #SqlResultSetMapping below code is working without sql result set mapping
Query q = em.createNativeQuery(queryStr);
List<Object[]> resultList = q.getResultList();
for (Object[] result : resultList) {
entityObj.setReason(result[0].toString);
//rest attribute will convert from result[1].toString to corresponding
// data type and set to entity object
}
I have two classes.
One class extends the other.
Both classes will be persisted in the database.
Why am I still getting : Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.ct.www.model.Bt column: q_Id (should be mapped with insert="false" update="false")
Questions.class
#Entity
#Table(name="Questions")
#Access(value = AccessType.FIELD)
public class Questions implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
//#Access(value= AccessType.FIELD)
private String q_Id;
#Column(name="q_type")
private String q_Type;
#Column(name="q_lang")
private String q_lang;
#Access(value = AccessType.PROPERTY)
public String getQ_Type() {
return q_Type;
}
public void setQ_Type(String q_Type) {
this.q_Type = q_Type;
}
#Id
#Column(name="q_Id")
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Access(value = AccessType.PROPERTY)
public String getQ_Id() {
return q_Id;
}
public void setQ_Id(String q_Id) {
this.q_Id = q_Id;
}
#Access(value = AccessType.PROPERTY)
public String getQ_lang() {
return q_lang;
}
public void setQ_lang(String q_lang) {
this.q_lang = q_lang;
}
}
BT.class
#Entity
#Table(name="BT")
#Access(value = AccessType.FIELD)
public class BT extends Questions implements Serializable{
private static final long serialVersionUID = 1L;
#Access(value = AccessType.FIELD)
// #Id
// #Column(name="q_Id")
private String q_Id;
#Access(value = AccessType.PROPERTY)
public String getQ_Id() {
return q_Id;
}
public void setQ_Id(String q_Id) {
this.q_Id = q_Id;
}
// #OneToOne(cascade = CascadeType.ALL)
// #PrimaryKeyJoinColumn
// #JoinColumn(name="q_id")
// #MapsId
private Questions question;
public Questions getQuestion() {
return question;
}
public void setQuestion(Questions question) {
this.question = question;
}
}
One of my use case is
Questions and BT will be persisted separately into corresponding tables in MySQL (Questions table and BT table).
BT is a type of Question. So I decided to extend it.
Both table has a primary key which is Id, and my DAO class will first insert in Questions table and use same Id for BT class which later inserts into BT table.
Extending a base class which is an Entity will cause this problem.
You can:
Remove the common mapped fields/properties from the child class
Add #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) above parent class for your use case.
Refer to Section 2.11.4 in Hibernate-5.3.1.Final User Guide for example code.
If you need different generation strategy in parent and child, you can override the getQ_Id() method in child and implement that.
I am using envers in my project to audit data.
Now I want to access changed data with audit query.
My pojo class for table is below
#Entity
#Audited(withModifiedFlag=true)
#Table(name = "INSTRUMENT", uniqueConstraints = #UniqueConstraint(columnNames = "INSTRUMENT_NAME"))
public class Instrument implements java.io.Serializable {
private long instrumentId;
private String instrumentName;
private WorkflowState workflowState;
#Id
#Column(name = "INSTRUMENT_ID", unique = true, nullable = false, precision = 22, scale = 0)
public long getInstrumentId() {
return this.instrumentId;
}
public void setInstrumentId(long instrumentId) {
this.instrumentId = instrumentId;
}
#Column(name = "INSTRUMENT_NAME", unique = true, nullable = false, length = 50)
public String getInstrumentName() {
return this.instrumentName;
}
public void setInstrumentName(String instrumentName) {
this.instrumentName = instrumentName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STATUS", nullable = false)
public WorkflowState getWorkflowState() {
return this.workflowState;
}
public void setWorkflowState(WorkflowState workflowState) {
this.workflowState = workflowState;
}
}
Now I tried to access this with audit query as
AuditQuery query = reader.createQuery().forRevisionsOfEntity(Instrument.class, false, true)
.add(AuditEntity.property("status").hasChanged());
List list= query.getResultList();
So at the time of accessing getResultList() , Its throwing Exception as follows
SqlExceptionHelper: Fail to convert to internal representation
I figured it out, this is because in my db Instrument.status column is as String data Type. While here I am using Join.
So please tell me how to write query to resolve this problem
PROBLEM is How to write Audit Query if my table has foreign key (class property have join dependency).
Join table WorkflowState discription is as follows
public class WorkflowState implements java.io.Serializable {
private BigDecimal stateId;
private Workflow workflow;
private String stateName;
//getters and setters
And it has a join column too i.e "workflow" .
Use workflowState rather than status. The API is based on you specifying the property name and not the column name.