Transform MySQL select to Criteria API - java

I have the following select statement in MySQL (sorry for the column/tables names):
SELECT a1.* FROM A a1
LEFT JOIN A a2
ON a1.DD_ID = a2.DD_ID
and a1.PRD = a2.PRD
AND a1.VN < a2.VN
LEFT JOIN B bb
ON a1.id = cc.del_id
WHERE a2.DD_ID is null
AND bb.del_id is null;
Here are the entities:
#Entity
#Table(name = "A", uniqueConstraints = {
#UniqueConstraint(columnNames = {"DD_ID", "VN", "PRD"})})
public class A
implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "VN", nullable = false)
private Short vn;
#Column(name = "PRD", nullable = false)
#NotNull
private String prd;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "DD_ID", nullable = false)
#NotNull
private DD dd;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "A")
private Set<B> bs;
#Override
public boolean equals(final Object pOther)
{
...
}
#Override
public int hashCode()
{
...
}
// getters and setters
}
#Entity
#Table(name = "B")
public class B
implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "DEL_ID", nullable = false)
#NotNull
private A a;
#Override
public boolean equals(final Object pOther)
{
...
}
// getters and setters
}
and I want to implement it using Criteria API, but I have troubles implementing the self left join from the statement.
Any suggestions?

Related

JPA Hibernate Clildren with #EmbeddedId not loadded on Weblogic server but loadded in integration test

I have a problem with JPA and Hibernate where I have 2 entities that are in relation of 1 to many.
On local host on the integraiton test using H2 the things are as they should (children are loaded), when deployed into the weblogic server that is using Oracle as DB, the children are not loaded.
Any idea on this?
The entities definitions are:
#Entity
#Table(name = "TB_MASTER")
#Data
#ToString
#NoArgsConstructor
public class Case implements Serializable {
private static final long serialVersionUID = 1919288768119684307463L;
#Id
#Column(name = "ID", nullable = false, length = 55)
private String id;
#Column(name = "CODE_ADR", nullable = false, length = 100)
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "id.masterId")
#EqualsAndHashCode.Exclude
private Set<MasterReference> references = new TreeSet<>();
}
The EmbeddedId class:
#Data
#AllArgsConstructor
#EqualsAndHashCode
#NoArgsConstructor
#Embeddable
public class MasterReferenceId implements Serializable, Comparable {
#ManyToOne(optional = false)
#JoinColumn(name = "MASTER_ID", nullable = false)
#ToString.Exclude
#EqualsAndHashCode.Exclude
private Master masterId;
#Column(name = "REF", nullable = false, length = 42)
private String reference;
#Column(name = "SHORCUT", nullable = false, length = 100)
private String shortcut;
#Column(name = "REF_DATE")
private Date refDate;
#Column(name = "REF_BACK", length = 1)
#Convert(converter = BooleanToNumberConverter.class)
private Boolean refBack;
#Column(name = "REF_DATA_ROW", length = 2000)
private String refDataRow;
#Override
public int compareTo(Object o) {
if (o instanceof MasterReferenceId && ((MasterReferenceId) o).getReference() != null && ((MasterReferenceId) o).getReference() != null) {
return ((MasterReferenceId) o).getReference().compareTo(this.getReference());
}
return 0;
}
}
The cild entity:
#Entity
#Table(name = "TB_MASTER_REFERENCE")
#Data
#ToString
#NoArgsConstructor
public class MasterReference implements Serializable, Comparable {
private static final long serialVersionUID = -517596820344348395356L;
#EmbeddedId
private MasterReferenceId id;
#Column(name = "UPDATE_DATE", nullable = false)
private Date updateDate;
#Column(name = "COMMENTS", length = 4000)
private String comments;
#Override
public int compareTo(Object o) {
if (o instanceof MasterReference && ((MasterReference) o).getId() != null) {
return ((MasterReference) o).getId().compareTo(this.getId());
}
return 0;
}
}
Try this instead:
public class MasterReference implements Serializable, Comparable {
#EmbeddedId
private MasterReferenceId id;
#ManyToOne(optional = false)
#JoinColumn(name = "MASTER_ID", nullable = false)
#MapsId("masterId")
private Master masterId;
..
}
public class MasterReferenceId implements Serializable, Comparable {
private String masterId;
..
}
Change the mappedBy in the OneToMany on references to just "masterId" so that it uses the reference mapping instead of trying to use the embeddedId.

JPA: Use a multiple One-to-many relationships with composite keys

I have these entities:
Run entity:
#Entity
#Table(name = "run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "runId")
public class Run implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "run_id")
private Long runId;
#Column(name = "status")
private Integer status;
#Column(name = "create_date")
private Date date;
#Column(name = "config_id")
private Long configId;
#Column(name = "stream_id")
private Long streamId;
#OneToOne(mappedBy = "run", cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "run_id", unique = true, nullable = true, insertable = true, updatable = true)
private StreamRun streamRun;
...
}
and StreamRun entity:
#Entity
#Table(name = "stream_run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "streamId")
public class StreamRun implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
private Long streamId;
#Column(name = "run_id", insertable = false, updatable = false)
private Long runId;
#Column(name = "stream_name")
private String streamName;
#OneToOne
#JoinColumn(name = "run_id")
private Run run;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "stream", orphanRemoval = true, targetEntity = JobRun.class)
private List<JobRun> jobs = new ArrayList<>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "streamRun", orphanRemoval = true, targetEntity = StreamEvent.class)
private List<StreamEvent> events = new ArrayList<>();
....
}
and JobRun entity:
#Entity
#Table(name = "jobs_run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
#IdClass(JobRunKey.class)
public class JobRun implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
private Long id;
#Id
#Column(name = "run_id", insertable = false, updatable = false)
private Long runId;
#Column(name = "name")
private String name;
#Column(name = "type")
private String jobType;
#Column(name = "script")
private String script;
#Column(name = "status")
private Integer status;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "run_id", referencedColumnName = "run_id"), #JoinColumn(name = "job_stream_id", referencedColumnName = "id") })
private StreamRun stream;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobDependencyRun.class)
public List<JobDependencyRun> dependencies = new ArrayList<>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobEvent.class)
public List<JobEvent> events = new ArrayList<>();
....
}
And all the columns are defined in the MySQL database, Table job_run have composite key of (id and run_id).
The problem is in JobRun entity:
If I define "run_id" field as #ID then an exception appear (when insert)
Parameter index out of range (8 > number of parameters, which is 7).
If I define it without #ID then an exception appear (when update)
Duplicate entry '4-78' for key 'PRIMARY'
If I remove the whole field definition from entity since it is foreign key then the exception will be:
Unable to find column with logical name run_id
"Although the column exists in the table".
Please, can anyone help me?
Do I do anything wrong in the code?
I have managed to find a solution, by modifying JobRun entity as below, and change\access the value of runId from direct setter and getter method.
#Entity
#Table(name = "jobs_run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
#IdClass(JobRunKey.class)
public class JobRun implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
private Long id;
#Id
#Column(name = "run_id")
private Long runId;
#Column(name = "job_stream_id")
private Long streamId;
#Column(name = "name")
private String name;
#Column(name = "type")
private String jobType;
#Column(name = "script")
private String script;
#Column(name = "status")
private Integer status;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "run_id", referencedColumnName = "run_id", insertable = false, updatable = false),
#JoinColumn(name = "job_stream_id", referencedColumnName = "id", insertable = false, updatable = false) })
private StreamRun stream;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobDependencyRun.class)
public List<JobDependencyRun> dependencies = new ArrayList<>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobEvent.class)
public List<JobEvent> events = new ArrayList<>();
...
}

Many-to-many relationship with composite keys, extra column in Hibernate

I have 3 data table:
Applications {id_app, version, name}
Customers {org_id, name}
Associations {id_app, version, org_id, state}.
Applications has a composite primary key (id_app, version), the primary key for Customers is org_id and Associations has a composite primary key (id_app, version, org_id).
In my java application I have the following classes:
#Entity
#Table(name = "Applications")
#IdClass(ApplicationId.class)
public class Application implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID_APP", nullable = false)
private String idApp;
#Id
#Column(name = "VERSION", nullable = false)
private String version;
#Column(name = "NAME")
private String name;
#OneToMany(mappedBy = "idPk.appPk", fetch = FetchType.LAZY) // cascade = CascadeType.ALL)
private List<Association> custApps;
// getters and setters
}
public class ApplicationId implements Serializable {
private static final long serialVersionUID = 1L;
private String idApp;
private String version;
//hashcode and equals
}
#Entity
#Table(name = "CUSTOMERS")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ORG_ID", unique = true, nullable = false)
private Integer orgID;
#Column(name = "NAME")
private String name;
#OneToMany(mappedBy="idPk.customerPk", fetch = FetchType.LAZY)
private List<Association> custApps;
//getters and setters
}
#Entity
#Table(name = "ASSOCIATIONS")
#AssociationOverrides({
#AssociationOverride(name = "idPk.appPk", joinColumns = #JoinColumn(name = "ID_APP")),
#AssociationOverride(name = "idPk.appPk", joinColumns = #JoinColumn(name = "VERSION")),
#AssociationOverride(name = "idPK.customerPk", joinColumns = #JoinColumn(name = "ORG_ID"))
})
public class Association implements Serializable {
private static final long serialVersionUID = 1L;
private AssociationId idPk = new AssociationId();
private String state;
public Association() {
super();
}
#EmbeddedId
public AssociationId getIdPk() {
return idPk;
}
#Transient
public Customer getCustomerPk() {
return idPk.getCustomerPk();
}
#Transient
public Application getAppPk() {
return idPk.getAppPk();
}
#Column(name = "STATE")
public String getState() {
return state;
}
//setters , hashCode and equals
}
#Embeddable
public class AssociationId implements Serializable {
private static final long serialVersionUID = 1L;
private Application appPk;
private Customer customerPk;
// here is the problem ?
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({ #JoinColumn(name = "ID_APP", referencedColumnName = "ID_APP"),
#JoinColumn(name = "VERSION", referencedColumnName = "VERSION") })
public Application getAppPk() {
return appPk;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="ORG_ID")
public Customer getCustomerPk() {
return customerPk;
}
//setter, hashCode and equals
}
What are the correct annotation? The relationship is many to many between Application and Customers and I create the Association table for that and for the extra column "state".
Now I receive this error: A Foreign key refering sla.model.Application from sla.model.Association has the wrong number of column. should be 2 .
Please help.
Done. I change the following:
In Association class:
#AssociationOverrides({
#AssociationOverride(name = "idPk.appPk", joinColumns = { #JoinColumn(name = "ID_APP", referencedColumnName = "ID_APP"),
#JoinColumn(name = "VERSION", referencedColumnName = "VERSION") }),
#AssociationOverride(name = "idPK.customerPk", joinColumns = #JoinColumn(name = "ORG_ID"))
})

Why Select query incrementing #Version

The version for the class Application is getting incremented after the execution of the following statement
Queue queue = queueDao.fetchQueueByApplicationId(application.getApplicationId());
It is a simple fetch query only and it should not increment the version of the call any how. But after above line execution the version is getting incremented unexpectedly for Application class
Could someone please help
Thanks.
Queue.java
#Entity
#Table(name = "queue")
#NamedQuery(name = "queueByApplicationId", query = "SELECT q from Queue q WHERE q.application.applicationId = ?")
public class Queue implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "queue_id", unique = true, nullable = false)
private Long queueId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created", nullable = false, length = 19)
private Date created;
#Column(name = "created_by")
private Long createdBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated", length = 19)
private Date updated;
#Column(name = "updated_by")
private Long updatedBy;
#Version
#Column(name = "version", nullable = false)
private Integer version;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "application_id")
private Application application;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "queue", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private List<QueueAssignedToRole> queueAssignedToRoles;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "queue", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private List<QueueAssignedUser> queueAssignedUsers;
getter setter ....
}
Application.java
#Entity
#Table(name = "application")
public class Application implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long applicationId;
private Integer version;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "application_id", unique = true, nullable = false)
public Long getApplicationId() {
return this.applicationId;
}
public void setApplicationId(Long applicationId) {
this.applicationId = applicationId;
}
#Version
#Column(name = "version", nullable = false)
public Integer getVersion() {
return this.version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
ApplicationQueueDaoImpl.java
#Repository
public class ApplicationQueueDaoImpl extends AbstractDao<Queue> {
private static final Logger LOGGER = LogManager.getLogger(ApplicationQueueDaoImpl.class);
#Override
public Queue fetchQueueByApplicationId(Long applicationId) {
LOGGER.debug("Fetching Queue information for applicationId {}", applicationId);
List<Queue> queues = executeNamedQuery("queueByApplicationId", Queue.class, applicationId);
return CollectionUtils.isEmpty(queues) ? null : queues.get(0);
}
}
AbstractDao.java
protected <T> List<T> executeNamedQuery(String queryName, Class<T> resultType, Object... positionalParams) {
TypedQuery<T> query = entityManager.createNamedQuery(queryName, resultType);
DAOUtils.setPositionalParams(query, positionalParams);
return query.getResultList();
}

Hibernate creating Composite Key instead of using Identifier

I have an Entity FooBar which serves as the #ManyToMany join table for Foo and Bar entities including some additional information.
#Entity
#Table(name = "foo_bar")
public class FooBar
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
protected Long id;
#Column(name = "someInfo", nullable = true)
private String someInfo;
#ManyToOne(optional = false)
private Foo foo;
#ManyToOne(optional = false)
private Bar bar;
//getters, setters, and toString()
}
#Entity
#Table(name = "foo")
public class Foo
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
protected Long id;
#OneToMany(mappedBy = "foo", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<FooBar> fooBars;
//Foo has a number of other fields
#Column(name = "orderIndex", nullable = false)
private int orderIndex;
#Column(name = "upgradeDirection", nullable = false)
#Enumerated(EnumType.STRING)
private Order direction;
#ManyToOne(optional = false)
private SomeEntity e;
//getters, setters, and toString()
}
#Entity
#Table(name = "bar")
public class Bar
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
protected Long id;
#OneToMany(mappedBy = "bar") //TODO specify a cascade and fetch attribute
private Set<FooBar> fooBars;
//Bar contains a number of other fields
#Column(name = "value", nullable = false)
private String value;
//getters, setters, and toString()
}
When Hibernate creates the table is has columns 'id', 'someInfo', 'foo_id', and 'bar_id'. 'foo_id' and 'bar_id' are used in as a composite key instead of using the 'id' field, any idea why?

Categories