#ManyToMany NamingStrategy - java

There is the following case:
#javax.persistence.Entity
#javax.persistence.Table(name = "another_table")
public class Table {
...
#javax.persistence.ManyToMany
public java.util.Set<sth> getSth() {
return this.sth;
}
While making the query JPA thinks correcly that there is many to many table "another_table_sth" but expects to find column "table_id" in it as defined by the class name. However, there is actually a column another_table_id as defined by the #javax.persistence.Table annotation.
How to define this case in the naming strategy?

Related

Using Index annotation on superclass with Hibernate

I have an abstract superclass which every Entity on my domain is a subclass of it.
Using DB schema generation, I want to create an Index for each Entity, on a field on the superclass, and without using the Table annotation on every subclass.
My superclass
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = SEQUENCE)
private Long surrogateId;
#Index(name="id_index") // Every subclass should inherit this index, with its own name
#Column(unique = true, updatable = false, nullable = false)
private UUID id = UUID.randomUUID();
An example of subclass
#Entity
public class Customer extends BaseEntity {
...
}
I tried so far:
use the Table annotation with #Index on the superclass, but Hibernate
doesn't seem to use that annotation if it is not marked with #Entity.
For example
#Table(indexes = {#Index(name="index_id", columnList = "id")})
No SQL statements are generated.
use the deprecated #Index annotation with a name "id_index", but only one index
is created on startup (the db raises an error that this index already
exists for other entities). Some generated SQL statements:
Hibernate: create index id_index on "customer" ("id")
Hibernate: create index id_index on "user" ("id")
2020-02-15 17:47:26,620 WARN o.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl - GenerationTarget encountered exception accepting command : Error executing DDL "create index id_index on "customer" ("id")" via JDBC Statement
org.postgresql.util.PSQLException: ERROR: relation "id_index" already exists
Any ideas on how to do this without too much code duplication?
Thanks
The only way I can see to do this - and it appears more trouble than it is worth to simply avoid placing an #Table annotation on each Entity - is to create a custom dialect and override the getIndexExporter() method:
public class MyPostgreSQLDialect extends PostgreSQLXXDialect{
#Override
public Exporter<Index> getIndexExporter() {
return new MyIndexExporter(this);
}
}
to return a customized Exporter, most likely extending org.hibernate.tool.schema.internal.StandardIndexExporter
public class MyIndexExporter extends StandardIndexExporter{
public MyIndexExporter(Dialect dialect){
super(dialect);
}
#Override
public String[] getSqlCreateStrings(Index index, Metadata metadata) {
//looks like you'd need to paste the whole code from superclass method
//and alter the index name accordingly
indexNameForCreation = index.getTable().getQualifiedTableName() +
"_" + index.getName();
//in the default implementation it is simply index.getName()
}
}
Alan Hay answer may work but it seems a bit of overengineering... So I decided to not use schema generation and use Liquibase instead, so I can have more control over the database.
Anyway, If anyone is having the same problem with schema generation, I tried with #Index (using eclipselink) and it worked, so this issue is only in Hibernate.

Getting abstract superclass mapped by a View using Hibernate returns Invalid column name

The situation is as following. Say I've got a Kid, and I want to get his Parent. The abstract Parent is situated in a View. The Parent can either be a Mother or a Father. The Mother is also defined in a View.
#Entity
public class Kid extends DomainObject {
private IParent theParent;
#ManyToOne(fetch = FetchType.LAZY, targetEntity = Parent.class)
#JoinColumn(name = "TheParentId")
public IParent getTheParent() {
return theParent;
}
#Override
public void setTheParent(IParent theParent) {
this.theParent = theParent;
}
}
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
#Table(name = "Parent")
public abstract class Parent {
}
#Entity
public class Mother extends Parent {
}
So, using Hibernate, I try to retrieve the Mother-object by calling getTheParent() on Kid:
from Kid hobj left join fetch hobj.theParent pa
This works fine in the database. But when running this via Hibernate, it returns SQL exception: Invalid column name(UNKNOWN)
There are a few pointers which can be the cause. In the old database, Mother and Father were Table's instead of Views. My guess is that Hibernate understood the link because of foreign keys. Changing the Parent from Table to View broke the application. But searching around points out that Hibernate treats View's and Table's equally (to some extent). Why does getting the exact query being used by Hibernate work when entered directly, but not when using Hibernate?
The problem seemed to be in the select-clause of the query. When adding multiple objects to the select column (running deeper with more tables then Kid, Mother and Father), Hibernate would get confused. When I only used the Kid-object (and fill up items using Kid.getX().getY().getZ()... ), Hibernate had no problem fetching everything.
Seems to be a bug in Hibernate.

EclipseLink JPA inheritance without discriminator column

I have a Client and Affiliate class, inheriting from Person class. Joined inheritance strategy type is being used - each of them sharing primary key with the parent class. As there's no discriminator column we chose to use DescriptorCustomizer and ClassExtractor. But it doesn't really give any idea how it works, also, the code doesnt seem to compile. It would be nice if someone gives a nice example with code snippet for understanding.
According to the mentioned documentation:
If you are mapping to an existing database, and the tables do not have
a discriminator column you can still define inheritance using the
#ClassExtractor annotation or <class-extractor> element. The class
extractor takes a class that implements the ClassExtractor
interface. An instance of this class is used to determine the class
type to use for a database row. The class extractor must define a
extractClassFromRow() method that takes the database Record and
Session.
we need to annotate the root entity in a hierarchy with user defined using the class extractor:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#ClassExtractor(PersonClassExtractor.class)
public abstract class Person {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int age;
// ...
}
Notice that we don't use #Customizer annotations since as this is not required in case of JOINED inheritance strategy:
If a class extractor is used with SINGLE_TABLE inheritance, the rows
of the class type must be able to be filtered in queries. This can be
accomplished by setting an onlyInstancesExpression() or
withAllSubclassesExpression() for branch classes. These can be set
to Expression objects using a DescriptorCustomizer.
The class extractor must be able to determine and return the class type from the database row.
In general we need a replacement of a discriminator column, i.e.
column name unique for a given entity type among others
criteria based on values of a given column of the root entity
Suppose that each of inherited entity type in a hierarchy has a column with unique name:
#Entity
public class Client extends Person {
#Column(name = "CLIENT_SPECIFIC")
private String clientSpecific;
// ...
}
#Entity
public class Affiliate extends Person {
#Column(name = "AFFILIATE_SPECIFIC")
private float affiliateSpecific;
// ...
}
then class extractor may look as follows:
public class PersonClassExtractor extends ClassExtractor {
#Override
public Class<?> extractClassFromRow(Record databaseRow, Session session) {
if (databaseRow.containsKey("CLIENT_SPECIFIC")) {
return Client.class;
} else if (databaseRow.containsKey("AFFILIATE_SPECIFIC")) {
return Affiliate.class;
} else {
return Person.class; // this should never happen
}
}
}
retrieve a list of clients and affiliates
List<Person> polymorphicResults = em.createQuery("SELECT p FROM Person p")
.getResultList();
retrieve a list of affiliates or clients respectively
List<Affiliate> concreteResults = em.createQuery("SELECT a FROM Affiliate a")
.getResultList();
List<Client> concreteResults = em.createQuery("SELECT c FROM Client c")
.getResultList();

How to set uniqueness level to my JPA entities using Hibernate?

Suppose I have 2 JPA entities:
#Entity
public class OwnerEntity {
private List<OwnedEntity> subEntities
// ...
}
#Entity
public class OwnedEntity {
private String quasiUniqueSid;
private OwnerEntity ownerEntity
// ...
}
As you can see they have a many to one relationship: an OwnerEntity can have many OwnedEntitys.
What I want to achieve is to assign each OwnedEntity a unique sid based on its owner. So I can have for example 2 owned entities with the same quasiUniqueSid but they cannot have the same owner. Do Hibernate has some built-in functionality for this kind of problem? I can remember other ORMs (not Java related) which could do this thus my question. I'm using the latest Hibernate version (4.1.8)
It seems you need a composite key, like this:
#Entity
#Table(uniqueConstraints=#UniqueConstraint(columnNames={"quasiUniqueSid","ownerEntity_id"}), name="myUniqueConstraint")
public class OwnedEntity {
...
String quasiUniqueSid;
#ManyToOne
OwnerEntity ownerEntity;
...
}
A full documentation you can find here.
If you wanna explicitly define the column name for ownerEntity, you can use:
#JoinColumn(name="ownerEntity_id")

HIbernate loads subclasses along with classes

I am using Hibernate to connect to my database.
I have an inheritance structure in my application.The problem is that when i do a query like "from Animal", it does a left outer join for the class Animal,its sub classes and all the associations for Animal and its subclasses.
How do i avoid this situation.I want to load the data only when i specify it through a fetchmode in my criteria query?
Yes, Hibernate supports polymorphic queries. From the documentation:
14.8. Polymorphic queries
A query like:
from Cat as cat
returns instances not only of Cat, but
also of subclasses like DomesticCat.
Hibernate queries can name any Java
class or interface in the from clause.
The query will return instances of all
persistent classes that extend that
class or implement the interface. The
following query would return all
persistent objects:
from java.lang.Object o
The interface Named might be
implemented by various persistent
classes:
from Named n, Named m where n.name = m.name
These last two queries will require
more than one SQL SELECT. This means
that the order by clause does not
correctly order the whole result set.
It also means you cannot call these
queries using Query.scroll().
This is the default behavior (called implicit polymorphism) and Hibernate supports both implicit and explicit polymorphism:
Implicit polymorphism means that instances of the class will be
returned by a query that names any
superclass or implemented interface or
class, and that instances of any
subclass of the class will be returned
by a query that names the class
itself. Explicit polymorphism means
that class instances will be returned
only by queries that explicitly name
that class. Queries that name the
class will return only instances of
subclasses mapped inside this
<class> declaration as a
<subclass> or <joined-subclass>.
For most purposes, the default
polymorphism="implicit" is
appropriate. Explicit polymorphism is
useful when two different classes are
mapped to the same table This allows a
"lightweight" class that contains a
subset of the table columns.
This can be configured at the class level. Use polymorphism="explicit" if you are if you are using xml mappings, see 5.1.3 Class. Use Hibernate's #Entity annotation if you're using annotations, see 2.4.1. Entity. Below an example:
#javax.persistence.Entity
#org.hibernate.annotations.Entity(polymorphism = PolymorphismType.EXPLICIT)
#Inheritance(strategy = InheritanceType.JOINED)
public class Foo {
...
}
Assume you have a class structure as follows:
class Animal { }
class Dog : Animal { }
class Cat : Animal { }
then when you select all Animals, you'd expect to also load all Dogs and Cats. After all they are Animals.
A different story are the associations. You can created you mappings such that the associations are lazy load instead of eager load.
Basically it's the default ORM inheritance design pattern used by Hibernate called class inheritance (all the classes are mapped to a single table), if you want to change that you can google:
- single class hierarhy or table per class (this will map every class to a separate table in the DB)
- concrete class hierarhy (this will map only the concrete implementations to a table).
To avoid multiple joins during class hierarchy fetching you can apply SINGLE_TABLE hierarchy mapping strategy, and then define secondary tables on subclasses with SELECT fetching strategy. However, this turns you "heavy join" model into "N+1 select" model. The example:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = Super.DISCRIMINATOR_COLUMN, discriminatorType = DiscriminatorType .STRING, length = 255)
public class Super {
public static final String DISCRIMINATOR_COLUMN = "classname";
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected long id;
#Column(updatable = false, insertable = false)
protected String classname;
protected String superProp = "superProp";
public long getId() {
return id;
}
public String getClassname() {
return classname;
}
public String getSuperProp() {
return superProp;
}
public void setSuperProp(String superProp) {
this.superProp = superProp;
}
}
#Entity
#SecondaryTable(name = SubA.TABLE)
#Table(appliesTo = SubA.TABLE, fetch = FetchMode.SELECT)
public class SubA extends Super {
public static final String TABLE = "SUBA";
#Column(table = TABLE)
protected String subAProp = "subAProp";
public String getSubAProp() {
return subAProp;
}
public void setSubAProp(String subAProp) {
this.subAProp = subAProp;
}
}
#Entity
#SecondaryTable(name = SubB.TABLE)
#Table(appliesTo = SubB.TABLE, fetch = FetchMode.SELECT)
public class SubB extends Super {
public static final String TABLE = "SUBB";
#Column(table = TABLE)
protected String subBProp = "subBProp";
public String getSubBProp() {
return subBProp;
}
public void setSubBProp(String subBProp) {
this.subBProp = subBProp;
}
}
And what SQL is done on from Super HQL query:
select [...] from SUPER super0_
select super_1_.subaprop as subaprop1_83_ from SUBA super_1_ where super_1_.id=1
select super_2_.subbprop as subbprop1_84_ from SUBB super_2_ where super_2_.id=2
More about this approach and general hibernate performance hints you can read in my article.

Categories

Resources