How to override an annotation-defined table name in JPA? - java

I have tables that have this annotation structure in my application and I use JpaRepository for CRUD operations.
#Entity
#Table(name = "FOO")
public class Foo implements Serializable {
…
}
But I need to override only the table name (not any of the #Column etc. attributes) from an orm.xml or properties file without changing the actual code. I've searched and I couldn't find a way to do it in Spring Data JPA. Am I missing something here or it is not supported?

Firstly, Spring Data is not a JPA provider but simply a 'helper' library providing a wrapper round common persistence operations. The JPA specification however does provide a mechanism for overriding annotations via an XML mapping file. So assuming your provider (Hibernate, EclipseLink, OpenJPA or whatever) fully implements the JPA specification then you should be able to do this.
However it would appear that you cannot override only the table name: unless your column names are mapped to the default values then, as far as I can see, you need to specify each column in the mapping file - which is slightly inconvenient I suppose.
The book Pro JPA 2 : Mastering the Java Persistence API notes:
The metadata-complete attribute is an attribute on the entity,
mapped-superclass, and embeddable elements. If specified, all
annotations on the specified class and on any fields or properties in
the class will be ignored, and only the metadata in the mapping file
will be considered as the set of metadata for the class. When
metadata-complete is enabled, the same rules that we applied to
annotated entities will still apply when using XML-mapped entities.
For example, the identifier must be mapped, and all relationships must
be specified with their corresponding cardinality mappings inside the
entity element.
So you will need an entry in your orm.xml like the below, adding other attributes as required.
<entity-mappings>
<entity class="examples.Foo" metadata-complete="true">
<table name="NEW_FOO"/>
<attributes>
<id name="id"/>
</attributes>
</entity>
</entity-mappings>

Related

Set Hibernate access strategy globally?

According to the Hibernate documentation, the placement of the #Id annotation determines how Hibernate will access the entity (field or accessors)
As a JPA provider, Hibernate can introspect both the entity attributes (instance fields) or the accessors (instance properties). By default, the placement of the #Id annotation gives the default access strategy. When placed on a field, Hibernate will assume field-based access. Place on the identifier getter, Hibernate will use property-based access.
Is it possible to define this globally via a property (To avoid having to place a #Access(AccessType.FIELD) on each entity or embeddable)?
I found this related question, but that is for Spring Boot specifically.
You can create a file called orm.xml and put it to the classpath in directory META-INF.
In that file you can set default values. For example the access type:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings>
<persistence-unit-metadata>
<access>PROPERTY</access>
</persistence-unit-metadata>
</entity-mappings>
You can find the XML Schema here: https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/resources/org/hibernate/jpa/orm_2_2.xsd

What name of generated database by liferay?

Where are tables that generated database by Liferay through service.xml?. I don't see it in my Postgres. There are so many tables, I tried to find it but it not found. Anyone can help me, thanks
Unless you explicitly specify the table name in the entities that you declare in service.xml, the table names are constructed with the namespace and entity name.
<service-builder package-path="com.liferay.docs.guestbook">
<namespace>GB</namespace>
<entity name="Guestbook" local-service="true" uuid="true">
...
would generate GB_Guestbook as table name.
From the very well documented DTD:
<namespace>
The namespace element must be a unique namespace for this component.
Table names will be prepended with this namespace. Generated JSON
JavaScript will be scoped to this namespace as well (i.e.,
Liferay.Service.Test.* if the namespace is Test).
<entity> Child of service-builder
An entity usually represents a business facade and a table in the
database. If an entity does not have any columns, then it only
represents a business facade. The Service Builder will always generate
an empty business facade POJO if it does not exist. Upon subsequent
generations, the Service Builder will check to see if the business
facade already exists. If it exists and has additional methods, then
the Service Builder will also update the SOAP wrappers.
If an entity does have columns, then the value object, the POJO class
that is mapped to the database, and other persistence utilities are
also generated based on the order and finder elements.
...
(and you'll find more hints, e.g. explicit table names, in that document)
Notes:
If you declare that the entities are stored in an external (non-Liferay) datasource, no tables will be created.
Also, some versions of Liferay automatically updated the database structure on deployment of a new plugin version (with updated persistence layers), while others don't do this automatically (it's a developer feature anyways, not good for large - production - amount of data)

How would I map an #Entity with a hbm.xml?

I in a situation where I need to override some fields in a #Entity class but I can't edit the class. It just so happens that this #Entity class is mapped in a way that I don't think it's possible to partially override it. I was wondering what would be the steps to overriding this class completely or maybe partially if possible.
The class:
org.broadleafcommerce.profile.core.domain.AddressImpl
I've used a hbm.xml and a orm.xml but I'm not exactly sure how to configure them properly.
The book Pro JPA 2 : Mastering the Java Persistence API notes:
The metadata-complete attribute is an attribute on the entity,
mapped-superclass, and embeddable elements. If specified, all
annotations on the specified class and on any fields or properties in
the class will be ignored, and only the metadata in the mapping file
will be considered as the set of metadata for the class. When
metadata-complete is enabled, the same rules that we applied to
annotated entities will still apply when using XML-mapped entities.
For example, the identifier must be mapped, and all relationships must
be specified with their corresponding cardinality mappings inside the
entity element.
So you will need an entry in your orm.xml like the below, adding all other persistent attributes as required (partial override is not possible).
<entity-mappings>
<entity class="com.Foo" metadata-complete="true">
<table name="FOO"/>
<attributes>
<id name="id"/>
</attributes>
</entity>
</entity-mappings>

Is there any annotation available for eager loading at class level when we are not using any mapping?

Is there any annotation available for eager loading at class level when we are not using any mapping ? I know that this is available in XML configuration where we have
<code>
<class name="A" lazy="false">
</class>
</code>
(I know that association Mapping annotations have attributes as fetch=FetchType.EAGER for applying this to any Entity objects one by one. But, here I am not using any mapping.)
My requirement for eager loading is based on the design pattern I have used in my project which is Template where I have several operations with more than one session created and destroyed, so I require eager loading for using all the operations at one client class.
If class is not associated with any of the other class, and you are using session.get() method, it will load the class eagerly.

JPA using variable Schema name in annotations

I'm using the Java Persistence API to describe tables from my database that i will manipulate in my code.
However, the schema used is not be the same depending on where my project will be installed. So, when I use the annotations, I would like that the SCHEMA field was a variable, but I can't make it:
#Entity
#Table(name = "TABLE_NAME", schema = schemaVariable, catalog = "")
How can I achieve that?
Is it possible with the persistence.xml file?
No, this is not possible. You can only use compile-time constants (which are all primitives and String) in annotations.
You can use final variables:
public class DatabaseMetadata {
public static final SCHEMA = "MySchema";
}
and then use it in annotation:
#Table(name = "TABLE_NAME", schema = DatabaseMetadata.SCHEMA, catalog = "")
but I think it's not what you wanted.
PS. On the other hand, there can be find examples of using i.e. Spring EL in annotations (see #Value annotation), but this requires custom annotation processor. AFAIK none of JPA providers gives you such ablility.
Putting schema information (like table, column, schema names) in java classes is a bad idea any time IMHO (forcing recompile if you want to deploy elsewhere). You could put that info in orm.xml and just deploy a different orm.xml dependent on your deployment requirement.
As for persistence.xml you would be dependent on your JPA provider having a persistence property that defined the default schema/catalog. I know DataNucleus JPA (what I use) has this, but no idea for Hibernate
If you know that you would be using different schemas, I'd suggest to use 2 mapping files and define
<entity-mappings>
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>HR</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
...
</entity-mappings>
In this way you will be able to easily change schemas, without any changes in the application code.

Categories

Resources