Eclipselink JPA + #Mutitenant + #Inheritance Insert Op Failing - Inconsistent Behavior - java

#MappedSuperClass
public abstract class BaseMappedSuperClass {
#EmbeddedId
private EmbeddedId id;
}
#Entity
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "typeCol")
public abstract class Vehicle extends BaseMappedSuperClass{
private String name;
}
#Entity(name = "Cycle")
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#DiscriminatorValue(value = "Cycle")
public class Cycle extends Vehicle {
private String bellType;
}
#Entity(name = "Bus")
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#DiscriminatorValue(value = "Bus")
public class Bus extends Vehicle {
private String gearType;
}
I have the above entity structure and if I try to do an insert op on the entity Cycle or Bus, it fails inconsistently, because of the missing primary key field (id).
When I tried to debug the JPA codebase, I figured that the tenant discriminator, which is tenant_id in my case is not appended to the table name prefix for the embeddedId field 'Id' and the discriminator column field 'typeCol'.
What is more interesting is that this behavior is not consistent. If I restart my application and try, it works. If I restart again and try,it does not work.
Any help would be appreciated. Version of eclipse link used is 2.5.1.
What is the logic behind the order in which the entities are processed to initialize the metadata?

Related

DB column name generation problem (missing column) when OneToMany is in the abstract class

Situation: Our application has been working properly with all the OneToMany associations, with the names, columns. We decided out of nowhere that we want our entity objects to change names just by adding DAO at the end. Object -> ObjectDAO.
What we did: We changed object names as planned. Then every entity got its #Table(name = "object") annotation, but now we are running into problems on our join tables. The names of columns are now generated badly - not using the given table's name. We want the column names to remain object_id instead of objectdao_id but #Table annotation does not do the trick.
nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing column [great_objectdao_id] in table [our_join_table]
I suppose column name generation was always taking into consideration not a table name, but object name then. What's making things harder, is our scheme where we have a BaseDAO and BaseObjectDAO objects inside of which the #OneToMany relations exist.
SomeOtherDAO object would have a some_other table name.
#Data
#MappedSuperclass
public abstract class BaseDAO {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonIgnore
private Long id;
(...)
}
#EqualsAndHashCode(callSuper = true, exclude = {"objectSources"})
#NoArgsConstructor
#Data
#MappedSuperclass
public abstract class BaseObjectDAO extends BaseDAO {
#JsonIgnore
#OneToMany
private Set<SomeOtherDAO> objectSources;
(........)
}
How do the objects extending BaseObjectDAO look like:
#EqualsAndHashCode(callSuper = true)
#Entity
#Table(name = "great_object")
#Data
#NoArgsConstructor
#Accessors(chain = true)
public class GreatObjectDAO extends BaseObjectDAO {
#EqualsAndHashCode(callSuper = true)
#Entity
#Table(name = "strange_object")
#Data
#NoArgsConstructor
#Accessors(chain = true)
public class StrangeObjectDAO extends BaseObjectDAO {
Question:
How do we force it to generate join tables with column names great_object_id and strange_object_id instead of great_objectdao_id and strange_objectdao_id?
The great_object table should remain to have the id column, and the change should only be visible in the join table.
join_table table column names we have and want to keep:
great_object_id, object_sources_id
You must use the #AttributeOverride annotation to change the name of the id column of the subclasses. See https://docs.oracle.com/javaee/6/api/javax/persistence/AttributeOverride.html
#EqualsAndHashCode(callSuper = true)
#Entity
#Table(name = "great_object")
#Data
#NoArgsConstructor
#Accessors(chain = true)
#AttributeOverride(name="id", column=#Column(name="great_object_id"))
public class GreatObjectDAO extends BaseObjectDAO {

more name attributes in Table

Im my SQL Server Database I have 8 tables with the same structure.
Now I want to insert in selected tables with one Java class.
#Entity
#Table(name = "tbl_Prognosen") //here I want to put all table-Names
public class AZBNachricht { ...
is this possible?
It isn't possible to accomplish what you described.
The closest to code reuse at the entity class level would be to use a #MappedSuperclass class where you place all the shared column names, etc and then extend that for each table implementation with differing table names.
#MappedSuperclass
public abstract class AbstractStructure {
#Id
#GeneratedValue;
private Integer id;
private String column1;
private String column2;
}
#Entity
#Table(name = "table1")
public class Entity1 extends AbstractStructure {
}
// ... so on

Unnable to save discriminator value. (JPA spring data + hibernate)

I have following situation:
Base class:
#Entity(name = "BaseEntity")
#Inheritance(strategy= InheritanceType.JOINED)
#DiscriminatorColumn(name="DISCR_COLUMN", discriminatorType = DiscriminatorType.STRING)
#Table(name = "base")
#DiscriminatorOptions(insert = true,force=true)
public abstract class Base implements Serializable {
Subclass:
#Entity(name = "SubclassEntity")
#DiscriminatorValue("A")
#Table(name="subclass")
#PrimaryKeyJoinColumn(name = "subclass_id", referencedColumnName = "base_id")
#DiscriminatorOptions(insert = true,force=true)
public class Subclass extends Base {
Repository:
public interface BaseRepository extends JpaRepository<Base, String>, JpaSpecificationExecutor<Base> {
The only problem I have is when I want to create a new Subclass
repository.saveAndFlush(Base base);
discriminator value is not saved and in DB appears NULL. I supposed it is set automatically by hibernate, isn't it ?
Attention: see comment below (!)
According to http://en.m.wikibooks.org/wiki/Java_Persistence/Inheritance section "Joined, Multiple Table Inheritance":
Hibernate does not support discriminator column for inheritance strategy: joined.

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

javax.persistence annotations and inheritance

I have 4 persistent classes which all have the same fields (exactly) the only 3 difference between them is 1) the class name, 2) the table name and 3) the data. i am aware that this might seem strange to some but trust me there is a good reason which i won't go into here.
now, i'm using hibernate annotations to configure my class which should work like so:
#Entity
#Table(name = "store")
public class Store
{
#Id
#Column(name = "unique_id")
protected String id;
#Column
protected String category;
...
}
.. and this does work, for a single stand-alone class, however there are many fields to map and i'd like to do it all in one hit for all four similar classes, ie:
public class StoreBase
{
#Id
#Column(name = "unique_id")
protected String id;
#Column
protected String category;
...
}
#Entity
#Table(name = "store1")
public class Store1 extends StoreBase
{}
#Entity
#Table(name = "store2")
public class Store2 extends StoreBase
{}
#Entity
#Table(name = "store3")
public class Store3 extends StoreBase
{}
#Entity
#Table(name = "store4")
public class Store4 extends StoreBase
{}
however when attempting this i get the following exception:
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: package.entities.Store1
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:672)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:546)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:291)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1292)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867)
i'm guessing this is because the super class is not being searched for the identifier?
is there a way to utilise inheritance in this context?
thanks, paul.
#MappedSuperclass
public class StoreBase
See docs for more info.
Have a look at #MappedSuperclass.

Categories