JPA join query with not in condition - spring-data-jpa

I'm having three tables Client, Task and TaskClient.
TaskClient is having client as foreign key.
Below is the bean:
#Entity
#Table(name="TaskClient")
public class TaskClient implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", unique=true, nullable=false)
private Integer id;
#ManyToOne
#JoinColumn(name="client", unique=false)
private Client client;
#ManyToOne
#JoinColumn(name="task", unique=false)
private Task task;
}
Below is TaskClientDAO:
#Repository
public interface TaskCliebtDAO extends JpaRepository<TaskClient, Serializable> {
#Query("")
public List<ClientBean> findClientAvailableForTask(Integer taskId);
}
Here I want to search all clients which are not associated with given template id.
For Example:
Client Task TaskClient
========= ====== ===================
id name id name id client task
----- ------ ----- ----- ----- -------- ------
1 c1 1 t1 1 1 1
2 c2 2 t2
3 c3
As above, I'm having 3 clients c1, c2 and c3. Same way I'm having 2 tasks t1 and t2.
Now TaskClient is holding mapping of Task and Client. In example client id 1 is associated with task id 1.
Now I want a query where i will give taskid and in return I want all available clients which are not associated with given task id in TaskClient table.
If I give task Id as 1, then i should get c2 and c3.
If i give task Id as 2, then i should get c1, c2, and c3.
Note: Client and Task bean doesn't have any reference to TaskClient bean
Please help.
Thanks in advance.

Related

Save entity with Spring data, persistence & db contraints

In my project I have e.g. an Employee which has several Mobile which has additional attributes, e.g.
Jon Doe, +911, private
Jon Doe, 123456, company
Jon Doe, 8978, company,
Mara Smith, 7888, private
Mara Smith, 458, company
and therefore I create
#Entity
public class Employee {
#Id
private int id;
#OneToMany(mappedBy="emp")
private List<Mobile> lstMobiles;
...
}
and for the Mobile I have
#Entity
#IdClass(MobileKey.class)
public class Mobile {
#Id
private String phoneNo;
#Id
#JoinColumn(name = "emp_id")
private Employee emp;
...
}
class MobileKey{
private String phoneNo;
private int emp;
....
}
The database has tables Employee, Mobile. The table Mobile first two columns are
emp_id (as int)
phoneNo (as String)
up till now nothing special except that the database has a foreign constraint, namely that the emp_id has to exist in the table Employee. Otherwise the phoneNo does not make much sense.
The major problem I'm facing right now is that I need to store Jon Doe or Mara Smith. If I use e.g.
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
}
with some Autowired variable as e.g. employeeRepo.save(newEmployee) than I get from the database a constraint violation. This is due to the fact that the Mobile is attempted to be inserted before the Employee is created in the table :-(
I guess that the design of Employee and the Mobile is somehow wrong - especially with the list and the relation. But could be as well be related with the Spring-Data configuration.

JPA how to aggregate columns in a join

I'm trying to implement a query like this in JPA:
SELECT
ta.field_aggr_1,
ta.field_aggr_2,
MIN(tb.date_inv) AS min_date_inv,
MAX(tb.date_inv) AS max_date_inv
FROM table_a ta
INNER JOIN table_b tb ON ta.idB = tb.id
GROUP BY
ta.field_aggr_1,
ta.field_aggr_2
The key point is the MIN and MAX functions that apply in one column of a joined table.
I've created the entities:
#Entity
#Table(name="table_a")
public class EntityA extends Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name="field_aggr_1")
private String field_aggr_1;
#Column(name="field_aggr_2")
private String field_aggr_2;
#ManyToOne
#JoinColumn(name="idB")
private EntityB entityB;
// Getters & Setters & HashCode & equals & toString
}
#Entity
#Table(name="table_b")
public class EntityB extends Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name="date_inv")
private String date_inv;
// Getters & Setters & HashCode & equals & toString
}
And in the service I want to create query:
EntityManager em = ...;
Root<EntityA> root = criteriaQuery.from(EntityA.class);
EntityType<EntityA> type = this.em.getMetamodel().entity(EntityA.class);
Join<EntityA, EntityB> join = root.join(type.getDeclaredSingularAttribute("entityB", EntityB.class));
List<Selection<?>> fields = new ArrayList<Selection<?>>();
// grouping fields
fields.add(root.<EntityA>get("field_aggr_1"));
fields.add(root.<EntityA>get("field_aggr_2"));
I've managed to include fields from the joined table,
fields.add(join.<EntityB>get("date_inv"));
BUT I haven't succeed in implement the min aggregation.
Thanks in advance for your answers!
I have managed to solve the question. First, I needed to have one more "root" and one more "entityType" for the joined entity:
Root<EntityB> rootB = criteriaQuery.from(EntityB.class);
EntityType<EntityB> typeB = this.em.getMetamodel().entity(EntityB.class);
With these, now I can do what I needed:
fields.add(builder.least(rootB.get(typeB.getDeclaredSingularAttribute("date_inv", String.class))));
fields.add(builder.greatest(rootB.get(typeB.getDeclaredSingularAttribute("date_inv", String.class))));
Hope that it helps someone!

Use different field for column in subclass of EJB entity

I need some help with the design of my entities.
I have a single table MyEntity with the following columns:
id | column1 | column2 | type
And the entity looks like:
#Entity
#DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING, name = "type", length = 255)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class MyEntity {
#id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
}
I would like to be able to have several entities inheriting from MyEntity and where each entity define how they use the columns column1 and column2. I would like to just use one single table for all my subclasses, and use the discriminator.
Like this (the following doesn't work):
#Entity
#DiscriminatorValue("TestClass1")
public class TestClass1 extends MyEntity {
#Column(name = "column1");
private long testField1;
#Column(name = "column2");
private long testField2;
}
#Entity
#DiscriminatorValue("TestClass2")
public class TestClass2 extends MyEntity {
#Column(name = "column1");
private long anotherName1;
#Column(name = "column2");
private long anotherName2;
}
I know this approach is not working, so I am reaching out to you guys for help.
EDIT
I have added the inheritance strategy to the MyEntity class, but SINGLE_TABLE is default, so it shouldn't make a difference.
I have tried two approaches:
1) If I don't put two fields MyEntity named column1 and column2, then I cannot create any named queries in MyEntity such as:
#NamedQuery(name=TEST, query="select m from MyEntity m where m.column1 = :val")
I get the following exception:
Caused by: org.hibernate.QueryException: could not resolve property: column1 of: com.test.MyEntity
I would really prefer to specify the queries in MyEntity and not in the subclasses.
2) If I put the fields (column1 and column2) in MyEntity, then I get the following exception:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.test.TestClass1 column: column1 (should be mapped with insert="false" update="false")
and I don't know how to move on from here. I'm not sure how to do the mapping, which is suggested in the exception message.

Updating a reference to a FK

I've searched for quite a while trying to figure this out. I am using JPA with EclipseLink (Oracle DB). I have a lookup table full of values. I have another table that has a FK relationship to that table. I can insert data fine, but when I try to update the table with a different value, I get an exception. I've tried setting the CASCADE_TYPE but that doesn't have any impact. I thought this would be simple, but maybe I'm missing something.
Lookup table:
public class SomeType implements Serializable {
#Id
#Column(name = "ID")
private Short id;
#Column(name = "TYPE")
private String type;
:
(getters & setters)
}
Contents:
ID Type
------------
1 Type1
2 Type2
3 Type3
: :
Person table (I've left out the Sequencing stuff for brevity):
public class Person implements Serializable {
#Id
#Column(name = "ID")
private Short id;
#JoinColumn(name = "SOME_TYPE", referencedColumnName = "ID")
#ManyToOne(optional = false)
private SomeType someType;
:
(getters & setters)
}
Inserting works fine:
EntityManager em;
:
Person p = new Person();
p.setSomeType(new SomeType(1));
em.persist(p);
That results in:
ID SOME_TYPE
------------------
1 1
But if I want to update Person to change the type:
EntityManager em;
:
Person p = em.find(1);
SomeType newtype = new SomeType(2);
p.setSomeType(newtype);
em.merge(p);
I see the following exception:
Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [SomeType] is mapped to a primary key column in the database. Updates are not allowed.
All I want is the value in the Person table to be updated, like:
UPDATE PERSON set SOME_TYPE = 2 where ID = 1;
Any assistance would be greatly appreciated. Thanks.
Thanks to Chris for answering this:
The update is possible if you use a reference to the managed instance of the object that you want to refer to, not create a new instance.
Person p = em.find(1);
p.setSomeType(em.find(SomeType.class, 2));
em.merge(p);

JPA - select with join - how to make two related tables

I have two tables with relacionship by id_employee.
--------------------------- ---------------------------
table employee table timesheet
--------------------------- ---------------------------
id_employee id_time
name_employee date_entry
--------------------------- quant_hour
id_employee
---------------------------
I need to do a select that returns all records from the table employe and hours in existing related table timesheet. Some employees do not have hours recorded in the timesheet table but should appear in the list because they are registered in the employee table.
What the JPQL query for this ?
Class Employee
#Entity
public class Employee {
#Id #GeneratedValue
private Long id_employee;
private String name_employee ;
//GETS and SETS
}
Class TimeSheet
#Entity
public class Timesheet {
#Id #GeneratedValue
private Long id_time;
private Double quant_hour;
private Date date_entry;
#ManyToOne
private Employee employee;
//GETS and SETS
}
Provided that both tables are mapped correctly,the Employee entity will have an attribute (or collection) of type Timesheet entity, therefore, you only need to get the list of employees:
SELECT e FROM Employee e
JPA automatically retrieves the Timesheet (or list of Timesheets) when you want to read it from the Employee entity.