Mapping database lookups to jpa entities - java

I have the following database tables: lookup and employee.
Lookup Table: structure with sample data.
class_name value description
GENDER_CODE 1 Male
GENDER_CODE 2 Female
BANK_CODE 1 HSBC
BANK_CODE 2 CityBank
Employee Table: structure with sample data.
id name gender_code bank_code
1 Yusuf 1 1
2 Maher 1 2
3 Suzan 2 1
What is the best way to map them into JPA entities?
I tried to map an abstract class to lookup table and use class_name column as discriminator for the subclasses Gender and Bank and reference the bank and gender as ManyToOne in the employee object.. but I'm getting a class cast exception when the gender_code and bank_code has the same value.
I tried to create views gender_lookup and Bank_lookup and map them directly to entities. Again hibernate complains that he can't find a table with such name.

I would try to map the lookuptable as n+1 separated entities, one abstract and n childs.
Mapped superclass should have SINGLE_TABLE inheritance and child classes need to declare the discriminator.
Something like this:
#MappedSuperclass
#DiscriminatorColumn(name = "class_name")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class LookupTable{
#Id
private Long vale;
#Column(nullable = false)
private String description;
// Getters and setters
}
#Entity
#DiscriminatorValue("GENDER_CODE")
public class GenderCode extends LookupTable() {
}
#Entity
#DiscriminatorValue("BANK_CODE")
public class BankCode extends LookupTable() {
}
#Entity
public class Employee{
#Id
private Long id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private GenderCode genderCode;
#Column(nullable = false)
private BankCode bankCode;
}

Related

How to extract value from "dictionary table" in JPA

I want to map two tables (ManyToOne connection) to one object in Java. One is primary CatalogObject table, the second is just a dictionary of possible types of objects. In Java I want to just have the String of type instead of mapping to a new object.
When I want to search for all objects in the class (f.e. "database") i have to first find an Id of type "database" and then find all CatalogObjects with this Id specified. Which looks a bit tedious.
CatalogObject Table:
ID, Name, Parent_ID (FK), TYPE_ID (FK)
Type Table:
ID, Type.
I've created a mapping with CatalogObject and CatalogObjectType classes, but CatalogObjectType class holds only single String right now.
public class CatalogObject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id")
CatalogObject parent;
String name;
#ManyToOne
#JoinColumn(name = "type_id")
CatalogObjectType type;
}
public class CatalogObjectType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
}
I want to replace CatalogObjectType with just a String value of the associated type. How to configure it for Hibernate/JPA? Can it be done?
What I want is:
public class CatalogObject implements Serializable {
...
String name;
#SomeAnnotation(name = "type_id")
String type;
}
Yes, you can map an entity to 2 database tables in 2 simple steps:
You need to annotate your entity with JPA’s #Table and #SecondaryTable annotations and provide the names of the first and second table as the value of the name parameters.
You need to annotate each attribute which you want to map to the secondary table with a #Column annotation and set the name of the secondary table as the value of the table attribute.
The #Table annotation defines the primary table to which the entity attributes get mapped by default.
The #SecondaryTable annotation specifies the second database table to which the entity gets mapped.
That’s all you need to do to map the 2 database tables to the one entity.
You can check this link for a detailed explanation with a sample.

Switching foreign key in hibernate is not working

TLDR;
I'm using spring boot and jpa.
I want to switch the foreign key of an object, in this case just switching the category of a vehicle.
But when i try to do that hibernate interprets it as if i'm trying to change the primary key of the category object instead of just switching the foreign key and I get this error
org.hibernate.HibernateException:identifier of an instance of abc.package.mode.Category was altered from 1 to 2
I have an entity Category which i'm using only for categorizing vehicle entity object.
#Entity
public class Category {
#Id
private Long id;
private String name;
}
Here is the Vehicle class which needs to be categorized.
#Entity
public class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator="dish_seq")
private Long id;
private String name;
private Integer price;
#ManyToOne(fetch = FetchType.EAGER, cascade=CascadeType.DETACH)
private Category category;
}
Lets say there's 3 categories,
'Sedan'
'Convertible'
'Hatchback'
If i have a car object,
Nissan-PT76, $30000, category: [id:1, name:Sedan]
When i try to change category manually to [id:2, name:Convertible] and persist it, i get
org.hibernate.HibernateException:identifier of an instance of abc.package.mode.Category was altered from 1 to 2
I cannot switch from one existing object to another. I have tried to look this up in the internet but i couldn't find the right keywords to search for this kind of relationship in hibernate, or does it not allow this kind of relationship at all?
Add column reference to your Category field in the Vehicle class
#JoinColumn(name = "category_id", nullable = false)

Composite discriminator jpa

I'm getting extra DTYPE in my query while my jps entities are structured as follow:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="PRODUCT_TYPE")
public abstract class Product extends Tent implements Serializable {
##ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PRODUCT_TYPE")
private TransType transType;
...
}
#Entity
#Table(name="CAR")
#DiscriminatorColumn(name="CAR_TYPE")
public class Car extends Product {
#Column(name = "car_ent_id", insertable = false, updatable = false)
private int carEntId;
....
}
Tent
|
Product
|
LEVEL-1 -->[Car_1_1] [car_1_2]....
|
LEVEL-2 -->[car_2_1] [car_2_2]...
So what I'm trying to achieve, discriminate all the entities at both LEVEL-1 and 2 together. Abstract class Product is having type which discriminating immediately 1 level down but when we are further extending level 1 entities at level 2. This's where I'm not having any clue.
Can we have custom non-db field defined in Product and assigning a value to each level-1 entity and for level-2 entities TYPE can work somehow?
Not really having any clue
Thanks

How to create #Index on #ManyToOne fields?

I want to create an #Index using hibernate. The index should consist of 3 fields, where some of them are nested within other entities. How can I achieve this?
#Table(name = "my_entity", indexes = {
#Index(name = "my_index", columnList = "id, person.firstname, person.lastname")
})
#Entity
public class MyEntity {
private Long id;
#ManyToOne
private Person person;
}
#Entity
public class Person {
#Id private Long id;
private String firstname;
private String lastname;
}
Result:
Caused by: org.hibernate.AnnotationException: Unable to create unique key constraint (id, person.firstname, person.lastname) on table my_entity: database column 'person.firstname', 'person.lastname' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
at org.hibernate.cfg.Configuration.buildUniqueKeyFromColumnNames(Configuration.java:1684)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1459)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857)
... 46 more
columnList takes an array of column names. Not an array of entity properties.
So you just need to provide the names of the columns in the test table, as you would do if you defined the index using SQL.
Documentation
What you try to do here is to create an index over 2 different tables (MyEntity and Person), thus it's impossible.
If you want to do that you have to embed the Person class like this :
#Table(name = "test", indexes = {
#Index(name = "my_index", columnList = "id, person.firstname, person.lastname")
})
#Entity
public class MyEntity {
private Long id;
private Person person;
}
#Embeddable
public class Person {
private String firstname;
private String lastname;
}
Note that I've remplaced #Entity by #Embeddable on the Person class, this way in the database you'll have one table named Test with the columns id, firstname and lastname

Mapping Multiple Classes to a Table in Hibernate, Without a DTYPE Column

I have two hibernate classes: a base class, and an extended class that has additional fields. (These fields are mapped by other tables.)
For example, I have:
#Entity
#Table(name="Book")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
public class B extends A {
public String node_ID;
// ...
}
public class Node {
public String ID; // maps to B.node_ID
// ...
}
How do I map this in Hibernate? The hibernate documentation states three types of inheritence configurations: one table per class, one table with a type column, and a join table -- none of which apply here.
The reason I need to do this is because class A is from generic framework that's reused over multiple projects, and class B (and Node) are extensions specific to one project -- they won't be used again. In the future, I may have perhaps a class C with a house_ID or some other field.
Edit: If I try the above pseudo-code configuration (two entities mapped to the same table) I get an error that the DTYPE column doesn't exist. The HQL has a "where DTYPE="A" appended.
This is possible by mapping the #DiscriminatorColumn and #DiscriminatorValue to the same values for both classes; this can be from any column you use that has the same data regardless of which type (not sure if it works with null values).
The classes should look like so:
#Entity
#Table(name="Book")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="published")
#DiscriminatorValue(value="true")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
#DiscriminatorValue(value="true")
public class B extends A {
public String node_ID;
// ...
}
For anyone who got here like me and does not want to have the dtype column but instead want to use the same table for more than one entity as is I would recommend using this
Basically you can create a Base like this
#MappedSuperclass
public abstract class BaseBook<T extends BaseBook> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
... any other variables, getters + setters
}
#Entity
#Table(name= "book")
public class BookA extends BaseBook<BookA>{
//Default class no need to specify any variables or getters/setters
}
#Entity
#Table(name= "book")
public class BookB extends BaseBook<BookB>{
#Column(name = "other_field")
private String otherFieldInTableButNotMapedInBase
... Any other fields, getter/setter
}
From the above we have created base super class which does not have any entity or table mapping. We then create BookA to be default with the Entity + Table mapping. From there we can create other Entities all extending from BaseBook but pointing to one table

Categories