How to persist JPA Map #OneToMany - java

I have an entity class which contains a map. The map references ranked entities of type Child.
#Entity
public class Parent implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#OneToMany
#JoinTable
private Map<String, Child> ranking;
}
#Entity
public class Child implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
}
I put objects into the map like so:
ranking.put(1, childA);
ranking.put(2, childB);
ranking.put(3, childA);
The Child class does not reference Parent. The map key is a ranking attribute I want to persist. I do not want the ranking attribute to be part of the Child class.
I want to achieve a join table (parent_child) where the columns look like:
|-------------| |----------| |---------------|
| parent | | child | | parent_child |
|-------------| |----------| |---------------|
| id | | id | | parent_id |
| ... | | ... | | child_id |
| | | | | ranking | <-- missing
|-------------| |----------| |---------------|
Actually, I do not get the rank column.
What am I missing? Is this even possible?

As hinted at above, you would need to create an additional Entity, say Relationship. You could then map this as Map like:
#Entity
public class Parent implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#OneToMany(mappedBy ="parent")
#JoinColumn(name = "parent_id")
#MapKeyColumn(name = "ranking")
private Map<String, Relationship> ranking;
}

You shouldn't use map in your case, for this problem you should create an entity for your parent_child and create #NamedQuery to return the rank with children

Related

How to fetch data from multiple tables in spring boot using mapping in Spring Boot's JPA repository

I have created four entity classes as:
#Entity
#Table(name = "DashboardRegionCountry")
public class DashboardRegionCountry implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "dashboardId")
private long dashboardId;
#OneToOne(targetEntity = Country.class)
#JoinColumn(name="countryId")
private Country country;
#OneToOne(targetEntity = Region.class)
#JoinColumn(name="regionId")
private Region region;
#ManyToOne()
#JoinColumn(name="dashboardId")
private Dashboard dashboard;
}
#Entity
#Table(name = "Dashboard")
public class Dashboard implements Serializable {
#Id
#Column(name = "dashboardId")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long dashboardId;
#Column(name = "dashboardName")
private long dashboardName;
#OneToMany(mappedBy= dashboard)
private List<DashboardRegionCountry> dashboardRegionCountry;
}
#Entity
#Table(name = "Country")
public class Country implements Serializable {
#Id
#Column(name = "countryId")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long countryId;
#Column(name = "shortName")
private String shortName;
#Column(name = "longName")
private String longName;
}
#Entity
#Table(name = "Region")
public class Region implements Serializable {
#Id
#Column(name = "regionId")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long regionId;
#Column(name = "shortName")
private String shortName;
#Column(name = "longName")
private String longName;
}
And the table schemas for the respective entities are as follows:
DashboardRegionCountry:
+----------------+---------------+
| Field | Type |
+----------------+---------------+
| id(PK) | Number(11) |
| dashboardId(FK)| Number(11) |
| countryId | Number(11) |
| regionId | Number(11) |
+-------------+------------------+
Dashboard:
+----------------+---------------+
| Field | Type |
+----------------+---------------+
| dashboardId(PK)| Number(11) |
| dashboardName | varchar(11) |
+-------------+------------------+
Country:
+-------------+---------------+
| Field | Type |
+-------------+---------------+
| countryId(PK)| Number(11) |
| shortName | Varchar2(10) |
| longName | Varchar2(10) |
+-------------+---------------+
Region:
+-------------+---------------+
| Field | Type |
+-------------+---------------+
| regionId(PK)| Number(11) |
| shortName | Varchar2(10 |
| longName | Varchar2(10) |
+-------------+---------------+
Basically, when user enters the dashboardId then we want to fetch, dashboardDetails along with the Region and respective countries presnt in that region. As stated above, I only have region and country Ids in my table and their names are present in other tables.
I want to display my sample output something like:
{
"dashboardId":20,
"DashboardRegionCountry": [{
"Region":"ASIA",
"dashboardId":["India","China"]
},
{
"Region":"NAM",
"dashboardId":["USA","Canada"]
}
]
}
I am trying to write JPA repository but was wondering is it possible to write something like:
#Repository
public interface DashboardRegionCountryRepository extends JpaRepository<DashboardRegionCountry, Long>{
List<Map<Long,Country>> findRegionBy_RegionId(Long dashboardId);
}
I am trying to fetch all the data in one query, any suggestion will be really helpful
Just get the corresponding DashboardRegionCountry using getById (check the reference documentation) and it will contain both associated Country and Region. If you then don't want to expose all Country and Region information in your entities I suggest you map them to a DTO that would be the model that you want to use while returning something on your controllers.
findByRegion_regionId try this this will work.

updating causes rows in one-to-many table to be duplicated instead of just being updated

I'm trying to modify part of a large amount of code written by someone else. I don't know what I'm doing.
I have a one-to-many relation ship: each entry in the code table can have many entries in the code_property table. I have tried to include a minimal example (below), but it is not executable because I don't have the skills to make it so.
My problem is that every time an entry in the code table gets updated, instead of just updating the associated entries in the code_property table, a new set is added instead (even if nothing has changes). There then seems to be some code that cleans this up.
mysql> select * from code_property where code_id=341965;
+----------+-----------------------+-------------------------------------+---------+
| id | name | property | code_id |
+----------+-----------------------+-------------------------------------+---------+
| 37187304 | incisivRunOptions | -access +rw | 341965 |
| 37187305 | designTabsActiveIndex | 1 | 341965 |
| 37187306 | incisivCompileOptions | -timescale 1ns/1ns -sysv -f files.f | 341965 |
| 37187307 | incisivRunOptions | -access +rw | 341965 |
| 37187308 | designTabsActiveIndex | 1 | 341965 |
| 37187309 | incisivCompileOptions | -timescale 1ns/1ns -sysv -f files.f | 341965 |
+----------+-----------------------+-------------------------------------+---------+
6 rows in set (0.00 sec)
I have two questions:
Can I not expect this to just update the code_property table without creating new entries? (If it were done right.)
Is it possible to see what is wrong based on the below code? If so, what?
#Entity
#Table(name = "code")
public class Code extends NamedDatedEntity implements Cloneable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Min(value = 0)
#Column(name = "id")
private long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
#JsonIgnore
private User user;
#OneToMany(mappedBy = "code", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#MapKey(name = "name")
private Map<String, CodeProperty> properties;
#Entity
#Table(name = "code_property")
public class CodeProperty extends Property implements Cloneable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Min(value = 0)
#Column(name = "id")
private long id;
#ManyToOne
#JsonIgnore
private Code code;

Is there any way to set String property of class depending on tablename?

I have two tables in my database, at "retail" schema, with indent column sets:
"vegetable_group":
+------------------+--------------------+
| (varchar) id | (varchar) value |
+------------------+--------------------+
| 1 | good_vegetables |
| 2 | bad_vegetables |
+------------------+--------------------+
"fruit_group":
+------------------+--------------------+
| (varchar) id | (varchar) value |
+------------------+--------------------+
| 3 | good_fruit |
| 4 | bad_fruit |
+------------------+--------------------+
also i have an enum in database type product_type as enum ('fruit', 'vegetable');
this is my entity:
#Data
#Entity
#Table(schema = "retail", name = "vegetable_group")
#SecondaryTables({
#SecondaryTable(schema = "retail", name = "fruit_group",
pkJoinColumns = #PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id")
)
})
public class Product implements Serializable {
private enum ProductType {
vegetable, fruit
}
#Id
#Column(name = "id")
private String id;
#Enumerated(EnumType.STRING)
ProductType productType;
#Column(name = "value")
private String value;
}
and simple ProductRepository
public interface ProductRepository extends JpaRepository<Product, String> {
}
I need to set somehow the value of product.productType depending on the table, from combined data...
Can i somehow simply do that?
Upd.
I'm using #SecondaryTable, because i need to get data from two tables using a single entity. For example, i have a Product with id 99. I don't know whether it is a vegetable or a fruit. The common approach for such process is to create two entities: Fruit and Vegetable and search them by id's. But database structure can't be changed so i use one entity Product, that gets data from both tables by unique id.

Exception querying inherited entities

In my db I have something similar:
+---------+
| answer |
+---------+ ----------------------->--+--------------+
| id +------) | answer_type_b|
---->-+--------------+ +--------------+
... | answer_type_a| | id |
+--------------+ | field_b |
| id | | ... |
| field_a |
| ... |
In my answer table I have common information, then I have two inheriting tables related to the parent table and having different specific fields.
I created model in my application using JPA 2 + Hibernate 4.2.6:
#Entity
public abstract class Answer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// ...
}
#Entity
public class AnswerA extends Answer{
#Column(name = "field_a")
private String fieldA;
// ...
}
#Entity
public class AnswerB extends Answer{
#Column(name = "field_b")
private String fieldB;
// ...
}
Now when I try to query all Answer entities I expect to get a collection with ALL the answers both Type A and Type B, instead I get an exception:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'answer0_.field_a' in 'field list'
I suppose this appens because there is no field_a field in parent table, so how can I solve this? Is there a way to query all the inheriting tables?
I solved following this interesting wiki-book.

JPA - Multiple columns discriminator

I have 3 tables like this in MySQL 5:
| PERSON |
| id | fullName | isEmp | isParent |
| EMPLOYEE |
| personId | code |
| PARENT |
| personId | job |
in which, Employee.personId and Parent.personId are foreign keys pointing to Person.id. An employee can also be a parent and vice versa. So how can I config using Annotation of JPA 2.0/Hibernate 3? Thanks!
If a Person can be both, you can't solve this through inheritance, because Java doesn't allow multiple inheritance. So you'll have to go with Aggregation, which is confusing on a semantic level, because it's has-a-parent instead of is-a-parent. But I'm afraid it's the way you'll have to go:
#Entity
public class Person{
#Id
private Long id;
#OneToOne(optional=true)
private Employee employee;
#OneToOne(optional=true)
private Parent parent;
public boolean isParent(){return parent!=null;}
public boolean isEmployee(){return employee!=null;}
}
#Entity
public class Employee{
#Id
private Long id;
#OneToOne(mappedBy="employee",optional=false)
private Person person;
}
#Entity
public class Parent{
#Id
private Long id;
#OneToOne(mappedBy="parent",optional=false)
private Person person;
}
(getters / setters etc. omitted)

Categories

Resources