Hibernate: Select Parent with Children Conditions - java

I have the following tables:
HEADER
---------------------------------
ID | STATUS
---------------------------------
1 | A
---------------------------------
2 | B
---------------------------------
DATA
--------------------------------------------------
ID | HEADER_ID | DKEY | DVALUE
--------------------------------------------------
1 | 1 | Age | 90
--------------------------------------------------
2 | 1 | Gender | M
--------------------------------------------------
3 | 1 | Score | 1000
--------------------------------------------------
1 | 2 | Age | 8
--------------------------------------------------
2 | 2 | Gender | M
--------------------------------------------------
3 | 2 | Score | 0
--------------------------------------------------
My JPA classes are:
**#Entity
#Table (name="HEADER")
public class Header {
#Id
#GeneratedValue
private int id;
#Column (name="STATUS")
private String status;
#OneToMany (cascade=CascadeType.ALL, orphanRemoval=true, mappedBy="header")
#LazyCollection(LazyCollectionOption.FALSE)
private Set<Data> dataList;
--- getters and Setters ---
}
#Entity
#Table (name="DATA")
publi class Data {
#Id
#GeneratedValue
private int id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "HEADER_ID", nullable = false)
private Header header;
#Column (name="DKEY")
private String key;
#Column (name="DVALUE")
private String value;
}**
Now, my problem is, I want to select a Header with Data that has "Age" equals to "90" and "Gender" equals to "M" using hibernate.
I tried the below approach:
select distinct h from Header h left join h.dataList dl where (dl.key = 'Age' and dl.value = '90') and (dl.key = 'Gender' and dl.value = 'M')
This returns me nothing because the condition "(dl.key = 'Age' and dl.value = '90') and (dl.key = 'Gender' and dl.value = 'M')" is executed in one "DATA" record which will always yield to false.
If i put or, "(dl.key = 'Age' and dl.value = '90') or (dl.key = 'Gender' and dl.value = 'M')" the result is wrong since I wanted to get those Header that Data satisfies Age and Gender conditions.
I had hours of headache because of this issue and I am out of solutions to try anymore. Hope someone could point me to the right direction/solution.
Thank yo so much.

You may try rewrite it this way:
select distinct h from Header as h
where h.id in
(select dl.header.id from Data as dl where dl.key = 'Age' and dl.value = '90')
and h.id in
(select dl.header.id from Data as dl where dl.key = 'Gender' and dl.value = 'M')

Related

org.hibernate.QueryException: illegal attempt to dereference collection in order by clause

I am trying to implement a simple HQL query of all objects of type A ordered by the following predicate :
a.getListB().get(0).getC().getLastname()
I tried the following HQL query :
select a_ from A a_ order by a_.listB.c.lastname
But I am getting the following exception :
org.hibernate.QueryException: illegal attempt to dereference collection
I have tried the following SQL query but I am getting inconsistent results :
select a.* from A a
left outer join B b on b.a_id=a.id
left outer join C c on b.uploaded_from=c.id
order by c.lastname=(select c_.lastname from A a_
left outer join B b_ on b_.a_id=a_.id
left outer join C c_ on b_.uploaded_from=c_.id
where a.id=a_.id limit 1) asc;
Code snipet :
#Entity
#Table(name = "A")
pubic class A {
private int id;
private List<B> listB;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
#OrderBy(clause = "id")
#OneToMany(fetch = FetchType.LAZY, mappedBy = "a")
public List<B> getListB() {
return this.listB;
}
}
#Entity
#Table(name = "B")
pubic class B {
private int id;
private A a;
private C c;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id", nullable = false)
public A getA() {
return this.a;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "uploaded_from", nullable = false)
public C getC() {
return this.c;
}
}
#Entity
#Table(name = "C")
pubic class C {
private int id;
private String lastname;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
#Column(name = "lastname")
public String getLastname() {
return this.lastname;
}
}
Any hints how can I work around this problem please either in HQL, Criteria or even native SQL?
I used the following tables to test one possible solution for your problem further below
create table A (
id UUID
);
create table B (
id UUID,
id_a UUID,
id_c UUID
);
create table C (
id UUID,
lastname varchar(63)
);
insert into A values
('aaaaaaaa-aaaa-aaaa-aaaa-000000000000'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000001'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000002'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000003'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000004');
insert into C values
('cccccccc-cccc-cccc-cccc-000000000000', 'C zero'),
('cccccccc-cccc-cccc-cccc-000000000001', 'C one'),
('cccccccc-cccc-cccc-cccc-000000000002', 'C two'),
('cccccccc-cccc-cccc-cccc-000000000003', 'C three'),
('cccccccc-cccc-cccc-cccc-000000000004', 'C four'),
('cccccccc-cccc-cccc-cccc-000000000005', 'C five'),
('cccccccc-cccc-cccc-cccc-000000000006', 'C six');
insert into B values
('bbbbbbbb-bbbb-bbbb-bbbb-000000000000', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000000'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000001', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000001'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000002', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000002'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000003', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000003'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000004', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000004'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000005', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000005'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000006', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000006'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000007', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000000'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000008', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000001'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000009', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000003', 'cccccccc-cccc-cccc-cccc-000000000002'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000010', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000003', 'cccccccc-cccc-cccc-cccc-000000000003'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000011', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000003', 'cccccccc-cccc-cccc-cccc-000000000004'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000012', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000004', 'cccccccc-cccc-cccc-cccc-000000000005'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000013', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000004', 'cccccccc-cccc-cccc-cccc-000000000006'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000014', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000004', 'cccccccc-cccc-cccc-cccc-000000000000'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000015', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000001'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000016', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000002'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000017', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000003');
Unique id_a entries are numbered via this intermediate select:
select id,id_a,id_c,ROW_NUMBER()
over (partition by id_a order by id_a) as rowNumber
from B as aggregate;
Result:
id | id_a | id_c | rownumber
--------------------------------------+--------------------------------------+--------------------------------------+-----------
bbbbbbbb-bbbb-bbbb-bbbb-000000000000 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000000 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000015 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000001 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000001 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000001 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000002 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000002 | 4
bbbbbbbb-bbbb-bbbb-bbbb-000000000004 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000016 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000002 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000003 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000003 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000005 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000005 | 4
bbbbbbbb-bbbb-bbbb-bbbb-000000000017 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000003 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000006 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000006 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000007 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000000 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000008 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000001 | 4
bbbbbbbb-bbbb-bbbb-bbbb-000000000011 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000010 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000003 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000009 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000002 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000012 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000005 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000013 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000006 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000014 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000000 | 3
(18 rows)
We can now obtain only the first C entry associated to a A entry by selecting only entries with rowNumber=1:
select *
from (
select id,id_a,id_c,ROW_NUMBER()
over (partition by id_a order by id_a) as rowNumber from B)
as aggregate
where aggregate.rowNumber=1;
Result:
id | id_a | id_c | rownumber
--------------------------------------+--------------------------------------+--------------------------------------+-----------
bbbbbbbb-bbbb-bbbb-bbbb-000000000000 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000000 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000004 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000017 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000003 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000011 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000012 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000005 | 1
(5 rows)
By joining C it is now possible to sort by lastname:
select aggregate.id_a,c.lastname
from (
select id,id_a,id_c,ROW_NUMBER()
over (partition by id_a order by id_a) as rowNumber from B)
as aggregate
join C as c on aggregate.id_c=c.id where aggregate.rowNumber=1
order by c.lastname;
Result:
id_a | lastname
--------------------------------------+----------
aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | C five
aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | C four
aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | C four
aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | C three
aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | C zero
(5 rows)
(Tested with Postgres 14.3)

JPA - 3 columns table to Entity Map

I'm looking for a way to group the query and put the other values into a map but I can' t find a way with a single table without joining. My scenario is the following:
CREATE TABLE metadata (
container_id INT NOT NULL,
metadata_key VARCHAR(50) NOT NULL,
metadata_value VARCHAR(255) NOT NULL,
PRIMARY KEY (container_id, metadata_key)
);
#container_id | #metadata_key | metadata_value
--------------+-------------------------+--------------------
15 | REPORTING_DATE | 20201231
15 | TYPES | T1,T2,Tx
11 | START_DATE | 20201231
1 | SHUTDOWN_ID | 12345
#Entity
#Table(name = "metadata")
public class Metadata {
#Id
#Column(name = "container_id")
private Integer containerId;
// metadata_key:metadata_value ???
private Map<String, String> metadata = new HashMap<>();
...
}
Is it possible?
You should consider 2 tables :
First table : container
#id | other stuff
--------------+-------------------------
15 | …
11 | …
1 | …
then other table for instance "metadata_key_value" like that :
#container_id | #metadata_key | metadata_value
--------------+-------------------------+--------------------
15 | REPORTING_DATE | 20201231
15 | TYPES | T1,T2,Tx
11 | START_DATE | 20201231
1 | SHUTDOWN_ID | 12345
Where « container_id » is FK of « container » table
Then the mapping should be like that :
#Entity
#Table(name = « container »)
public class Container {
#Id
#Column(name = « id »)
private Integer id;
#CollectionTable(name = "metadata_key_value», joinColumns =#JoinColumn(name = "container_id"))
#MapKeyColumn(name = "metadata_key")
#Column(name = "metadata_value")
private Map<String, String> metadata = new HashMap<>();
...
}

Hibernate, how to do a many-to-one mapping on a may-be-unique column, ignoring duplication

I have 2 Hibernate entities:
#Entity
class Car {
#ManyToOne
#JoinColumn(name = "brand_code")
private BrandReference brand;
}
#Entity
class BrandReference {
#Column(name = "brand_code")
private String brandCode;
}
The table BrandReference will have data like this:
row_id | brand_code | brand_name
--------------------------------
1 | TOYO | Toyota
2 | BENZ | Mercedes-Benz
3 | HOND | Honda
The column brand_code actually is expected to be unique. But I am in a situation where this expectation cannot be controlled. The data in table BrandReference is controlled by external party and it is unavoidable to have an error that cause the table to have more than 1 rows with the same brand_code
row_id | brand_code | brand_name
--------------------------------
1 | TOYO | Toyota
2 | BENZ | Mercedes-Benz
3 | HOND | Honda
4 | HOND | Gonda (Typo)
I don't like the program to crash on this situation. Is there a way to tell Hibernate to choose the row with the least row_id in case it found more than 1 rows with the matched brand_code when assigning a BrandReference to a Car. Something like this.
#Entity
class Car {
#ManyToOne
#JoinColumn(name = "brand_code")
#GetFirstRow(orderBy = "row_id")
private BrandReference brand;
}

Join two, three related tables by HQL

I have three related tables like below:
+-------------+---------+------------+
| customer_id | name | surname |
+-------------+---------+------------+
| 1 | Jan | Bielecki |
| 2 | Adam | Bielen |
.....
+----------+--------+---------------------+-------------+
| order_id | amount | date | customer_id |
+----------+--------+---------------------+-------------+
| 1 | 10.23 | 2017-02-15 00:00:00 | 1 |
| 2 | 20.56 | 2017-02-16 00:00:00 | 1 |
| 3 | 30.57 | 2017-02-17 00:00:00 | 2 |
| 4 | 40.52 | 2017-02-18 00:00:00 | 2 |
| 5 | 50.30 | 2017-02-19 00:00:00 | 1 |
.....
+-----------------+-----------+------------+----------+
| order_detail_id | item_name | item_price | order_id |
+-----------------+-----------+------------+----------+
| 1 | item 1 | 2.00 | 1 |
| 2 | item 2 | 2.50 | 1 |
| 3 | item 3 | 3.00 | 1 |
| 4 | item 4 | 4.00 | 2 |
| 5 | item 5 | 5.50 | 2 |
| 6 | item 6 | 7.60 | 3 |
| 7 | item 7 | 5.00 | 3 |
| 8 | item 8 | 3.00 | 4 |
| 9 | item 9 | 7.00 | 4 |
| 10 | item 10 | 8.00 | 4 |
| 11 | item 11 | 2.00 | 5 |
| 12 | item 12 | 2.50 | 5 |
.....
Firstly i'm fighting with connect first and second table. For connect surnames with sum of amount.
I'm trying like this:
select sum(o.amount) as totalSum
from Order as o,
Customer as c
join c.surname as surname
where c.orders:=o.customer
group by o.customer
order by sum(o.amount) desc
with changing to many ways this section: where c.orders:=o.customer
The most common error is NullPointerException.
Before done this in SQL:
Table customer_id <-> total_amount
SELECT customer_id,
SUM(amount) as total_amount,
COUNT(amount) as orders_quantity
FROM softhis_db.orders
GROUP BY customer_id;
Table customer_id <-> 3 most exp. orders + dates
SELECT orders.customer_id, orders.amount, orders.date
FROM orders_details
RIGHT JOIN orders
ON orders.order_id = orders_details.order_id
ORDER BY amount DESC
LIMIT 3;
Customer:
#Entity
#Table(name = "customers")
public class Customer {
#Id
#Column(name = "customer_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name", length = 50)
private String name;
#Column(name = "surname", length = 50)
private String surname;
#OneToMany(mappedBy = "customer")
private Set<Order> orders = new HashSet<>();
Order:
#Entity
#Table(name = "orders")
public class Order {
#Id
#Column(name = "order_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "date")
private Date date;
#Digits(integer = 5, fraction = 2)
#Column(name = "amount")
private BigDecimal amount;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "customer_id")
private Customer customer;
#OneToMany(mappedBy = "order")
private Set<OrderDetail> ordersDetails = new HashSet<>();
OrderDetail:
#Entity
#Table(name = "orders_details")
public class OrderDetail {
#Id
#Column(name = "order_detail_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Lon id;
#Column(name = "item_name", length = 50)
private String itemName;
#Digits(integer = 5, fraction = 2)
#Column(name = "item_price")
private BigDecimal itemPrice;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private Order order;
The point is how to do this properly in HQL ? Next step will be searching by surname and getting result like 'my target'.
My target is:
+---------+---------------+
| surname | sum of amount |
+---------+---------------+
|Bielecki | 150.40 |
|Bielen | 130.34 |
......
+-----------------------------------+--------------------+
| surname | 3 most expensive orders | date |
+-----------------------------------+--------------------+
|Bielecki | 120.23 |2017-02-15 00:00:00 |
|Bielecki | 80.20 |2017-02-18 00:00:00 |
|Bielecki | 20.20 |2017-02-19 00:00:00 |
+---------+-------------------------+--------------------+
|Bielen | 190.23 |2017-02-15 00:00:00 |
|Bielen | 80.20 |2017-02-18 00:00:00 |
|Bielen | 20.20 |2017-02-19 00:00:00 |
+---------+-------------------------+--------------------+
.....
Try these queries
SELECT
customers.surname
, SUM(amount) "sum of amount"
FROM
customers
INNER JOIN
orders
ON
customers.customer_id = orders.customer_id
GROUP BY
customers.surname
ORDER BY
customers.surname ASC
For the 3 most expensive orders per surname you need to use user variables to create ranking.
And filter on that ranking.
SELECT
customers.surname
, orders_ranked.amount AS "3 most expensive orders"
, orders_ranked.date
FROM (
SELECT
*
, (
CASE
WHEN
#customer_id = orders.customer_id
THEN
#rank := #rank + 1
ELSE
#rank := 1
END
)
AS
rank
, #customer_id := orders.customer_id
FROM
orders
CROSS JOIN (
SELECT
#customer_id := 0
, #rank := 0
)
AS
init_user_variables
ORDER BY
orders.customer_id ASC
, orders.amount DESC
)
AS
orders_ranked
INNER JOIN
customers
ON
orders_ranked.customer_id = customers.customer_id
WHERE
orders_ranked.rank <= 3
I figured out how to translate those SQL queries to HQL.
In order:
1.
select o.customer.surname, sum(o.amount) as s from Order as o group by o.customer
2.
select o.customer.surname, o.amount, o.date from Order as o, OrderDetail as od

Hibernate generates ghost entries for new child entities

I have a weird (to me anyway) issue with Hibernate which I can't make any sense of.
The code below is my attempt at modeling a ManyToOne relation with an attribute between the entities Case and Suggestion using an additional entity CaseToSuggestion with Case being my aggregate root:
#Entity
#Table(name = "sga_cases")
public class Case {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
// Business key
#Column(name = "caseid", unique = true, nullable = false)
private String caseId;
...
#OneToMany(mappedBy = "associatedCase", orphanRemoval = true, cascade = CascadeType.ALL)
private Set<CaseToSuggestion> associatedSuggestions = new HashSet<CaseToSuggestion>();
...
}
#Entity
#Table(name = "sga_suggestions")
public class Suggestion {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "suggestionid", unique = true, nullable = false)
private String suggestionId;
#Column(name = "localizationkey", nullable = false)
private String localizationKey;
#OneToMany(mappedBy = "associatedSuggestion", orphanRemoval = true, cascade = CascadeType.ALL)
private Set<CaseToSuggestion> caseMapping = new HashSet<CaseToSuggestion>();
...
}
#Entity
#Table(name = "sga_case2suggestion")
public class CaseToSuggestion {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "feedback")
private float feedback;
#ManyToOne
#JoinColumn(name = "caseid")
private Case associatedCase;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "suggestionid")
private Suggestion associatedSuggestion;
...
}
If I create new objects for the above entities, set the appropriate associations and then store them with the EntityManager everything works fine:
Case c = new Case(...)
Suggestion sugg = new Suggestion(...);
CaseToSuggestion case2sugg = new CaseToSuggestion(c, sugg, 1.0f);
c.getAssociatedSuggestions().add(case2sugg);
sugg.getAssociatedCases().add(case2sugg);
Followed by entityManager.persist(c);
If I want to add a new association to a Case that is already in the database I retrieve the Case and Suggestion entities I want to associate from the EntityManager and add them to a new CaseToSuggestion:
CaseToSuggestion c2s = new CaseToSuggestion(c, s, fb);
c.getAssociatedSuggestions().add(c2s);
s.getAssociatedCases().add(c2s);
Followed by entityManager.merge(c);
The the CaseToSuggestion entity is stored in the database but for every entry I get a "ghost entry" with a new generated id and all fields null:
+----+----------+--------+--------------+
| id | feedback | caseid | suggestionid |
+----+----------+--------+--------------+
| 3 | 1 | 3 | 1 |
| 4 | 1 | 4 | 2 |
| 5 | 1 | 5 | 2 |
| 6 | 0 | NULL | NULL |
| 7 | 1 | 6 | 2 |
| 8 | 0 | NULL | NULL |
| 9 | 1 | 7 | 2 |
| 10 | 0 | NULL | NULL |
+----+----------+--------+--------------+
Does anybody have an idea what might cause this?
OK, I got it.
Removing the OneToMany-Mapping in Suggestion altogether solved the problem for me.

Categories