How to create two-column unique key constrain with HBM mapping? - java

I have a hibernate mapping:
<properties name="lrt_bps_bpr_acs_uk" unique="true">
<many-to-one name="activitySummary" column="bps_acs_id" class="xyz.ActivitySummary"
unique-key="lrt_bps_bpr_acs_uk"/>
<many-to-one name="bestPractice" column="bps_bpr_id" class="xyz.BestPractice"
unique-key="lrt_bps_bpr_acs_uk"/>
</properties>
I expected that hibernate would create unique constraint on database for this mapping. Nothing like that happened however.
What am I doing wrong?

Seems like you do nothing wrong. We do it the same way in our project and it works fine.
I thought to have the same problem once because I couldn't find the constaints in our oracle DB because I thought the specified unique-key attribute value (in your case 'lrt_bps_bpr_acs_uk') is used as constraint_name in the DB. But that isn't the case (at least with oracle DB).

What's the actual DDL that Hibernate is generating? What would be the DDL if you remove the unique-key parameters? What's the Hibernate version?
From the documentation, it seems you are doing it correctly:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-declaration-properties

Dont specify name="lrt_bps_bpr_acs_uk" unique="true" in the properties element. It automatically takes it and applies the constraint with unique-key

Related

Using "SELECT FOR UPDATE OF" with Hibernate 4 & Postgres

I'm using Postgres 9.3.5 and recently updated the hibernate from 3.2 to 4.3.11.
As a result I can't run "SELECT... FOR UPDATE OF" queries,
and simply 'select.. for update' is not enough in my case since it returns
could not extract ResultSet. Reason: ERROR: FOR UPDATE cannot be applied to the nullable side of an outer join
The criteria I'm trying to use looks like this:
Criteria criteria = session.createCriteria(objectType).add(Restrictions.eq("name", objectName).ignoreCase());
I'm using the following locking:
in 3.2: criteria.setLockMode(LockMode.UPGRADE);
in 4.3.11: criteria.setLockMode(LockMode.PESSIMISTIC_WRITE);
I have an hierarchy of hibernate (& DB) objects which cause the hibernate perform several joins while constructing the above query.
the 'objectType' is a joined-subclass of the main class
<class name="BaseObject" table="BASE_OBJECTS">
While using hibernate 3.2 the final query (taken from Postgres logs) ended with: "for update of this_2_"
(when this_2_ is the alias given by hibernate to the main table (BaseObject) mapped in hbm.xml file)
After upgrading to 4.3.1.1 the same query returns the above mentioned exception.
which means the final query performed as for update (without the name of the table on which to perform the lock)
After an extensive look of the web I could find only that the "for update of" in hibernate with Postgres is not supported any more?
[https://hibernate.atlassian.net/browse/HHH-5654][2]
It seems very unlikely since it's quite an important sql feature and a big degradation in usage.
Am I missing something here?
02.09.15:
I'll try to clarify myself:
using an example given in the hibernate documentation
at
https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/inheritance.html
class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID">
<generator class="native"/>
</id>
<property name="amount" column="AMOUNT"/>
...
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
<key column="PAYMENT_ID"/>
<property name="creditCardType" column="CCTYPE"/>
...
</joined-subclass>
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
<key column="PAYMENT_ID"/>
...
</joined-subclass>
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
<key column="PAYMENT_ID"/>
...
</joined-subclass>
If I want to perform something like:
select p from Payment p where id=1
Hibernate will perform an outer join (on the key) on all tables .
Adding a lock (.setLockMode(LockMode.PESSIMISTIC_WRITE)) will lock the lines on the four tables (as 'For update'),
instead of only on table "Payments" ('for update of p') - which did happen in hibernate 3.2
So what We have, is that Something which was supplied earlier by hibernate, is not working any more, using their own mapping examples?
Thanks in advance
Marina
The issue was fixed in Hibernate 5.
Tested in 5.2.8.Final.

hibernate id generator AUTO_INCREMENT at h2 and MySQL in a cluster

For testing I'm using the H2 database.
For production it's MySQL.
I understrand that both support AUTO_INCREMENT (mysql / h2), but it seems like Hibernate doesn't work this way.
identity is supported for MySQL. Fine.
What about H2? Should I write my own generator or...? (using the org.hibernate.id.IdentifierGenerator interface as the doc says).
I must have a nice clean & quick way to get an ID (of type long by the way) from the database itself because the application is in a cluster (i.e several servers INSERT into the database at once)... that's why increment is definitely not for me.
Thanks!
You should just annotate your id property which needs the generated value with #GeneratedValue. This will automatically select the appropriate generation strategy for the database you're using. See GenerationType.AUTO for more details.
Your property will look like this:
#Id
#GeneratedValue
private long id;
Use the native generator, for example
<id name="id" type="int">
<column name="id_column" />
<generator class="native" >
<param name="sequence">id_column_sequence</param>
</generator>
</id>
The generator with the class native uses the best generation strategy for the database. In the case of MySql this is auto_increment, in the case of Oracle this is a sequence (and for H2 it also should be a sequence, but I've never tried, because I don't use H2). The generator parameter sequence only is used if it is useful, i. e. for MySql databases the parameter is ignored, and for Oracle it is used.
In that way you can use the same mapping file for different database types (at least as long as the table and column names are the same).

How to express a Serializable Blob type in a hibernate mapping file

I have a legacy application that uses hibernate for mapping objects into a database. It uses the Hibernate Mapping XML file to do so. The java class contains two properties abc and def that implement java Serializable. The mapping is defined this way:
<property name="abc" column="ABC" type="serializable" length="32672"/>
<property name="def" column="DEF" type="serializable" length="32672"/>
When I try to set this up with oracle, I get a nasty error "ORA-01754: a table may contain only one column of type LONG" which essentially is complaining about creating two 'long raw' columns in one table. Oracle does not like this. After reading up on the issue, the recommended approach is to use blobs instead of 'long raw' types.
My question is, how can I express in the hibernate mapping file to use a serializable type mapped into a blob column? I would think there would be a serializable_blob type but there does not seem to be.
I know this is possible with JPA annotations using #Basic and #Lob. It should also be possible using the hibernate mapping file. How can this be done in the hibernate mapping file?
Update:
The following do not work as Serializable works:
type=binary - This one expects a byte[]. Does not work for Serializable classes. Gives ClassCastException.
type=blob - - This one expects a java.sql.Blob. Does not work for Serializable classes. Gives ClassCastException.
type=materialized_blob - - This one expects a byte[]. Does not work for Serializable classes. Gives ClassCastException.
<property
name="data"
type="blob"
column="DATA"/>
...
should work.
Ok, did some more research following my comment above and, by Jove, I found it.
In Hibernate 3.5 + Spring 3.1, I used Spring's org.springframework.orm.hibernate3.support.BlobSerializableType. Now I'm upgrading to Hibernate 4.3, that option isn't available anymore. I did find the type to column mappings as OP, but in my application there are various Strings (legacy) that are mapped to BLOB fields.
So, as I reported in the comment above, I found the org.hibernate.type.SerializableToBlob type, which is parameterize. Below how I got the mapping to work (using good old-fashioned hbm.xml mappings)
<property name="description" column="TEXT">
<type name="org.hibernate.type.SerializableToBlobType">
<param name="classname">java.lang.String</param>
</type>
</property>
And that appears to do the trick. (the classname value should be the type of the attribute you are mapping, I think)

Setting database-agnostic default column timestamp using Hibernate

I'm working on a java project full of Hibernate (3.3.1) mapping files that have the following sort of declaration for most domain objects.
<property name="dateCreated" generated="insert">
<column name="date_created" default="getdate()" />
</property>
The problem here is that getdate() is an MSSQL specific function, and when I'm using something like H2 to test subsections of the project, H2 screams that
getdate()
isn't a recognized function. It's own timestamping function is
current_timestamp().
I'd like to be able to keep working with H2 for testing, and wanted to know whether there was a way of telling Hibernate "use this database's own mechanism for retrieving the current timestamp". With H2, I've come up with the following solution.
CREATE ALIAS getdate AS $$ java.util.Date now() { return new java.util.Date(); } $$;
CALL getdate();
It works, but is obviously H2 specific.
I've tried extending H2Dialect and registering the function getdate(), but that doesn't seem to be invoked when Hibernate is creating tables. Is it possible to abstract the idea of a default timestamp away from the specific database engine?
Could you try the following (without generated since your database is not generating the value):
<column name="DATE_CREATED" sql-type="timestamp" default="CURRENT_TIMESTAMP"/>
Have you tried using a <timestamp> mapping inside your <class>?
The docs aren't very clear but it sounds like this should result in mapping a column whose value is a timestamp.
You can specify if Hibernate should use a database generated value by setting either generated="insert" or generated="always".

Querying "extension tables" using Hibernate

I am having a querying issue in Hibernate. I have a table, 'test', with existing data. I have a requirement where I can not modify the schema of the test table, so I created another table, 'testExtension', whose primary key is a foreign key to the primary key of Test. Data in testExtension is a subset of the data in test. i.e. There will be less rows in 'testExtension' than in 'test'.
I have defined this relationship in a configuration file as follows:
<class name="Test" table="test">
<id name="testId" column="test_id">
<generator class="sequence">
<param name="sequence">test_id_seq</param>
</generator>
</id>
<property name="name"/>
<joined-subclass name="TestExtension" table="testExtension">
<key column="test_id"/>
<property name="summary" />
<property name="homepage"/>
</joined-subclass>
With this setup, I am able to create a TestExtension object in my Java program, populate it with data, 'save' it via Hibernate, and commit the transaction. And it correctly saves data in both Test and TestExtension.
My problem is occurring when I am trying to query data from these tables. Right now if I query for a particular test_id using the TestExtension.class to QBE, it will only return a row if that id exists in both Test and TestExtension. If I use the Test.class to QBE, it will return the row but I will not have access to any of the data stored in TestExtension.
My question is: how can I query these tables so that the results are based off a 'left outer join' of both Test and TestExtension? Any solution is appreciated, whether it's query by example, HQL, or something else (though preferably not raw SQL).
Thanks!
HQL is probably the easiest way to do this. Docs are here:
http://docs.jboss.org/hibernate/stable/core/reference/en/html/queryhql-joins.html
Sounds like what you might want to do is remap your relationships so that Test and TestExtension use a one-to-one relationship instead of inheritance. Then you can query for Test and TestExtension using a left outer join across the one-to-one.
If you use HQL to write a query for the Test class, it should do what you want. I assume QBE is effectively adding the class of your example entity as one of the query parameters.
So sth like:
from Test t where t.property = :value
should return either Test or TestExtension entities. Note that (at least with the versions of Hibernate I've used). In this case, Hibernate should immediately give you back the actual entities rather than a proxy too--- be aware that TestExtension entities can sometimes be returned as plain Test lazy-loading proxies.

Categories

Resources