I know you can ignore fields with #Transient annotation. I cannot find the way to denote that I don't want specific subclass to be persisted in database. Here are model classes:
Element class:
#Entity
public class Element {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
Long id;
#OneToMany(cascade = CascadeType.ALL)
private Map<String, Base> map;
private String text;
}
Base class:
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
public abstract class Base {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
Long id;
String type;
}
Foo class:
#Entity
public class Foo extends Base {
boolean flag;
}
Bar class:
#Entity
public class Bar extends Base {
int number;
}
Test object persisted:
Map<String, Base> map1 = new HashMap<>();
map1.put("foo-1" , new Foo());
map1.put("bar-1" , new Bar());
repo.save(new Element("element-1" , map1));
Table generated:
element table:
+------+-----------+
| id | text |
|------+-----------|
| 1 | element-1 |
+------+-----------+
element_map table;
+--------------+----------+-----------+
| element_id | map_id | map_key |
|--------------+----------+-----------|
| 1 | 1 | bar-1 |
| 1 | 2 | foo-1 |
+--------------+----------+-----------+
base table:
+------+--------+
| id | type |
|------+--------|
| 1 | <null> |
| 2 | <null> |
+------+--------+
foo table:
+--------+------+
| flag | id |
|--------+------|
| False | 2 |
+--------+------+
bar table:
+----------+------+
| number | id |
|----------+------|
| 0 | 1 |
+----------+------+
Is it possible to configure JPA to ignore Bar class and do NOT persist it in DB?
I tried adding #Transient annotation to all fields in Bar class but I end up with a bar table generated with only one field id inherited from the Base class. I would like to avoid having useless table database.
I tried removing #Entity annotation from Bar class but I end up with an exception each time a Bar object is persisted:
Caused by: org.springframework.orm.jpa.JpaSystemException: Unable to resolve entity name from Class [ch.smooth.hibernateinheritancehashmap.Bar] expected instance/subclass of [ch.smooth.hibernateinheritancehashmap.Base]; nested exception is org.hibernate.HibernateException: Unable to resolve entity name from Class [ch.smooth.hibernateinheritancehashmap.Bar] expected instance/subclass of [ch.smooth.hibernateinheritancehashmap.Base]
Any ideas how to specify part of class hierarchy to be transient?
I've isolated the problem for easier reproduction in a small spring-boot application on github: https://github.com/gladky/jpa-persistence-issue. Running mvn install will yield the exception which I mentioned.
Related
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.
I'm trying to find a solution for a this problem:
We have a table (code_list) in the database which contains all enum -like data.
Let us say we have an Affiliate that can have an AffiliateType and a LanguageCode.
We put all this in the code_list table where id_code_list field tells us if we are talking about AffiliateType or Languagecode and we can have a String or Integer identifier that tells us about which AffiliateType we are talking.
Example of the data in table:
| id_code_list | val_num | val_string | label |
| :----------: |:------: |:---------: | :-----:|
| TYP_AFF | 3 | 3 | Other |
| TYP_AFF | 1 | 1 | Divers |
| COD_LAN | 1 | 1 | French |
I tried to map this that way:
Code List Parent
#Entity
#Table(name = "CODE_LIST")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "ID_CODE_LIST")
public abstract class CodeListString {
#Id
#Column(name = "VAL_STRING")
protected String value;
#Embedded
protected Label label;
...
Affiliate Type:
#Entity
#DiscriminatorValue("TYP_AFF")
public class AffiliateType extends CodeListString{
public static final AffiliateType SOCIAL_SECRETARIAT = new AffiliateType("1");
public static final AffiliateType VARIOUS_SERVICES = new AffiliateType("2");
public static final AffiliateType OTHERS = new AffiliateType("3");
public static final AffiliateType SOPA = new AffiliateType("9");
public AffiliateType() {}
private AffiliateType(String value) {
super(value);
}
}
And my Affiliate entity:
#Entity
#Table(name = "AFF")
public class Affiliate {
#ManyToOne
#JoinColumn(name = "TYP_AFF")
private AffiliateType type;
But I'm getting this error:
org.hibernate.MappingException: Foreign key (FK7re97tvvbbo2km961gy9b5jw6:aff [typ_aff])) must have same number of columns as the referenced primary key (code_list [val_string,id_code_list])
So, is there a way to make this work or do you have other solution for this problem ?
PS: I'm using Hibernate and the solution like
#ManyToOne(targetEntity = AffiliateType.class)
#JoinColumn(name = "TYP_AFF")
#Where(clause = "ID_CODE_LIST='TYP_AFF'")
private AffiliateType type;
Doesn't work...
I've removed a dependency to a custom library and this worked.
I could not reproduce this error on a clean project.
Anyway this solution is really slow !
Below are the class definition
interface
public interface myInterface{
void myMethod1();
}
MyClass1 Class which implements above interface
#Entity
public class MyClass1 implements MyInterface{
#Id
private int id;
private String field1;
private String field2;
// Getter and setter
}
MyClass2 Class which implements above interface
#Entity
public class MyClass2 implements MyInterface{
#Id
private int id;
private String field3;
private String field4;
// Getter and setter
}
And finally the entity class which has a list with type parameter.
#Entity
public class MyClass{
#Id
priviate int id;
private String field5;
private String field6;
private List<? extends MyInterface> mylist;
//getter and setter
}
The generated class I'm looking at would look like something like below.
MyClass Table
-------------------------
id | field5 | field6
-------------------------
1 | abc | def
2 | abc | def
3 | abc | def
MyClass1 Table
-------------------------
id | field1 | field2 | myclass_fk
-------------------------
1 | abc | def | 2
2 | abc | def | 2
3 | abc | def | 1
MyClass2 Table
-------------------------
id | field3 | field4 | myclass_fk
-------------------------
1 | abc | def | 3
2 | abc | def | 1
3 | abc | def | 1
I tried to use #OneToMany on the list with targetType to MyInterface but it failed with error not a entity class.
EDIT
Can it be achieved with Hibernate OGM, preferably using graph or Mongo (document) based?
The problem is that Hibernate does not know from which table to load "mylist" when loading MyClass.
Take a look at https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/domain/inheritance.html.
I could achieve this using #ManyToAny annotation, though I needed to modify the class bit.
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
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.