Exception querying inherited entities - java

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.

Related

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.

Single table inheritance and relationship

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 !

Is it possible to avoid persisting of subclass with JPA?

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.

How to persist JPA Map #OneToMany

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

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