Hibernate use column name for property name - java

I am trying to generate JPA's from hibernate during my build process and everything is working fine except for the naming. The default it looks like is hibernate uses the class type for the property name. Is there a way to make it use the column name in the database as the property name?
for example in my DB i have a column name customer_org_type which references a table called valid_value to make sure the type is valid. When I generate the table it creates a property called:
public ValidValue validValue;
but I would like it to generate as:
public ValidValue customerOrgType;
Is there any way to have that?

I figured it out.
It required an entry in my hibernate.reveng.xml
Since it was a foreign key reference I just had to add the following:
<table catalog="my_catalog" name="user_info">
<foreign-key constraint-name="customer_org_type_id_fk" >
<many-to-one property="customerOrgType" exclude="false" />
</foreign-key>
</table>

Related

Hibernate's PhysicalNamingStrategy's toPhysicalSchemaName does not get called

I'm using Hibernate and trying to externalize the entity's table and column names to a .properties file. I've implemented the PhysicalNamingStrategy to map the entity properties and when executed everything works correctly (i.e., the methods toPhysicalTableName and toPhysicalColumnName get called for the table name and every mapped property, respectively).
However the toPhysicalSchemaName doesn't get called, even if I provide the annotation #Table(schema="SCHEMA_NAME"). The documentation says that
The PhysicalNamingStrategy will be applied regardless of whether the attribute explicitly specified the column name or whether we determined that implicitly. The ImplicitNamingStrategy would only be applied if an explicit name was not given.
I do not know if this applies to the schema name too. The toPhysicalSchemaName just won't get called no matter what I do. Should I be configuring the schema name differently for this to work?
Appreciate the help!
After some debugging found out that the hibernate-core 5.2.2.Final incorrectly creates the namespace. The org.hibernate.boot.model.relational.Namespace.java constructor has the following line
this.physicalName = new Namespace.Name(
database.getPhysicalNamingStrategy()
.toPhysicalCatalogName(name.getCatalog(), database.getJdbcEnvironment()),
database.getPhysicalNamingStrategy()
.toPhysicalCatalogName(name.getSchema(), database.getJdbcEnvironment())
);
The Name constructor expects the second argument to be the schema name, but the catalog gets passed again. Instead it should have been
this.physicalName = new Namespace.Name(
database.getPhysicalNamingStrategy()
.toPhysicalCatalogName(name.getCatalog(), database.getJdbcEnvironment()),
database.getPhysicalNamingStrategy()
.toPhysicalSchemaName(name.getSchema(), database.getJdbcEnvironment())
);
This is fixed in hibernate-core-5.2.10.Final.

Foreign relations are not generated while reverse engineering in hibernate

I tried to reverse engineer the POJOs from Database Schema using hibernate. While the classes and their DAO generated properly, I found that the relations between classes were not generated.
For ex, Friend table has reference to User table but the Friend table only contains the ids and not the actual User object.
I tried to find out the cause of it, but couldnt. One weird thing that i found was the .reveng.xml file did not contain any property values, if that is weird.
You need to specify both Friend and User table in .reveng.xml file
<table-filter match-name="Friend" />
<table-filter match-name="User" />
I think this will resolve your problem.

Trying to specify default value for property in hibernate

I'm getting the following error message from hibernate when attempting to insert a row into a table:
org.hibernate.exception.ConstraintViolationException: Column
'priority' cannot be null
I know that I could put a line into the code to set the value but there are many other instances where the program relies on the default value in the database (db is mysql).
I read somewhere that you can provide a default value in the hbm.xml file but hibernate is not recognizing it. Here's the corresponding section from JobQueue.hbm.xml
<property name="priority" type="integer">
<column name="priority" default="0" />
</property>
I suppose another option would be to modify the JobQueue.java file that gets generated (I'm using eclipse hibernate tools to auto generate the hibernate classes) but for now I'd like to try to get the hbm.xml configuration to work.
I'm using version 4.1.3 of the hibernate libraries and eclipse hibernate tools 3.4.0.x.
default="0" is only relevant for SchemaExport which generates the database schema. other than that hibernate completely ignores this setting. you could try to set not-null="true" for the column.
Unless you are not able to recreate the whole database schema, you can set the default value in the variable initialization.
In your model set the priority to 0 in the initialization.
In your class:
private Integer priority = 0;
I ended up modifying the JobQueue.java POJO to set the default value. To make sure that the Code Generation of hibernate tools wouldn't overwrite this change, I set it up so that the code generation generates the files in a temp folder and then the necessary files are copied over to the permanent source location.

JPA one-to-many unidirectional relationship using a join table

I would like to evaluate JPA on an existing project. The database model and the java classes exists and are currently mapped via self generated code. The database model and the java classes do not fit ideally together - but the custom mapping works well. Nevertheless the usage of JPA in general seems worth a try.
As you see I am new to JPA and have to do the work with xml configuration. Currently I am working on a one-to-many unidirectional relationship using a join table (please do not discuss this szenario here).
A (one - relationship owner) <-> AB (JoinTable) <-> B (many)
The tables look like this
A
--
ID
BREF
...
B
--
ID
...
AB
--
A_BREF (foreign key to a reference column in A which is NOT the id)
B_ID
I would like to define a unidirectional one-to-many relationship for class A.
class A {
private List<B> bs;
}
and did it like this:
<one-to-many name="bs">
<join-table name="ab">
<join-column name="a_bref">
<referenced-column-name name="bref" />
</join-column>
<inverse-join-column name="b_id">
<referenced-column-name name="id" />
</inverse-join-column>
</join-table>
</one-to-many>
Althoug this does not force an error it is not working. The problem is that the join table does not work on the ID column of A. The query to select the "B" entities works with the A.ID column value instead of the A.BREF column value to select the entities.
(How) can I make this mapping work (I use eclipselink 2.2.0)?
Thanks for any suggestion!
EDIT:
After looking at a link provided in #SJuan76 answer I slightly modified my mapping to
<one-to-many name="bs">
<join-table name="ab">
<join-column name="a_bref" referenced-column-name="bref" />
<inverse-join-column name="b_id" referenced-column-name="id" />
</join-table>
</one-to-many>
This now causes the following errors (tested with eclipselink 2.1.0 and 2.2.0)
eclipselink 2.1.0
Exception Description: The parameter
name [bref] in the query's selection
criteria does not match any parameter
name defined in the query.
eclipselink 2.2.0
Exception Description: The reference
column name [bref] mapped on the
element [field bs] does not
correspond to a valid field on the
mapping reference.
By the way - if I remove the referenced-column-name="bref" from the definition I get the same exception for the referenced-column-name="id" on the inverse-join-column element. So I doubt that I have understood referenced-column-name correct. I used it to specify the database column name of the tables which are related to the join table. Is this correct?
SOLUTION:
The final error in my szenario was that I did not have the BREF field definied in my class
class A {
private long bref; // missing !
private List<B> bs;
}
and in my orm.xml mapping file for this class
<basic name="bref">
<column name="bref" />
</basic>
I was not aware that I have to define the used join mapping referenced-column-name attributes somewhere in my mapping classes (as I also did not have the join-table itself or the name attributes of join-column/inverse-join-column mapped to a class or class members.)
Also the tip to check the case issue was helpful for me. I feel now quite to verbose in specifying my mapping as I overwrite all default (uppercase) mappings with lowercase values. As my database is not case sensitive I will use upper case notation if special mapping is needed to go with the default.
+1 for all!
Can you try defining the field as "BREF" or the same exact case used if you defined it on the attribute mapping, or you can try setting the eclipselink.jpa.uppercase-column-names persistence property to true. This is likely the issue with "id" when referenced-column-name="bref" is removed, since it is likely the field in the entity defaults to "ID".
In general JPA requires that the foreign keys/join columns reference the primary key/Id of the Entity. But, this should work with EclipseLink, so please include the SQL that is being generated, and if it is wrong, please log a bug.
How is the Id of A defined, is it just ID or ID and BREF?
You can use a DescriptorCustomizer to customize the ManyToManyMapping for the relationship and set the correct foreign key field name.

Is it possible create column name with white spaces using hibernate?

I am building data base system for electronic components. Unfortunatly other programs, that will use some of my tables need to have white spaces in column names. Ive tried in my hbm.xml file something like this with property:
...
property name="partGroup" column="part group" type="string"
...
of course hibernate wont create table with that column name.
Is there a way to do it using hibernate?
Thanks :]
There is a way, enclose the table names or column names with backticks. From the documentation:
5.4. SQL quoted identifiers
You can force Hibernate to quote an
identifier in the generated SQL by
enclosing the table or column name in
backticks in the mapping document.
Hibernate will use the correct
quotation style for the SQL Dialect.
This is usually double quotes, but the
SQL Server uses brackets and MySQL
uses backticks.
<class name="LineItem" table="`Line Item`">
<id name="id" column="`Item Id`"/><generator class="assigned"/></id>
<property name="itemNumber" column="`Item #`"/>
...
</class>
I had solved this problem as follows:
I had create following class:
import org.hibernate.cfg.DefaultNamingStrategy;
public class MysqlAdvancedNamingStrategy extends DefaultNamingStrategy{
#Override
public String columnName(String columnName) {
return "`"+super.columnName(columnName)+"`";
}
#Override
public String tableName(String tableName) {
return "`"+super.tableName(tableName)+"`";
}
}
I had setting as namingStrategy the "MysqlAdvancedNamingStrategy" at previous point.
The advantages of this solution is that you don't need to modify all annotation in you code.
It is also a clean solution because for some reason you may want have an application that access to same database "logic" in two different "database" (so with two style of escaping), with this solution you can intercept what database are you using and you can change the escaping strategy at "execution time", however the annotation are evalutated at "compilation time".
It is also a clean solution if you use Spring framework, with this you can change the escaping strategy without touching java code by setting a bean in session factory with id="namingStrategy" and class="util.MysqlAdvancedNamingStrategy".

Categories