java hibernate skip insert 'id' on insert - java

I have designed a table (in postgres) where 'id' column is autoincremented via its SEQUENCE entity.
But when I began use hibernate I met the problem .... due creating the insert statement, it use the follow statement
INSERT INTO mytable (id, name) VALUE (0, 'blablabla')
...
but I want it make somethink like that:
INSERT INTO mytable (name) VALUE ('blablabla')
... Postgres have to generate id automatically (at least when I ran such scripts withing sql editor, it worked)
I belive it can be configured, but I don't know how...
Here is my part of my .hbm.xml:
<hibernate-mapping>
<class name="com.cse.database.bean.Category" table="category">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<property name="name" type="string">
<column name="name" length="100" not-null="true" unique="true" />
</property>
</class>
</hibernate-mapping>

When you specify a <generator>, you're telling Hibernate how to create the ID. assigned means your application is doing it (which you don't want). You can specify a Hibernate class or even an application class to do it, which you don't want either. identity means the database does it for you, which is what you want. In some databases you can use sequence (which will query the sequence generator to get the ID, then write the record), and Hibernate allows you to use native to specify the most applicable for your DB.
<id name="id" type="int">
<column name="id" />
<generator class="identity" />
</id>
apparently works in this case.

assigned means that you explicitely assign the ID of the entity, which is not the case. The problem with these auto-generated IDs in postgreSQL, AFAIK, is that it's not possible to get the last generated ID, and that Hibernate has no way to get the ID assigned to the entity after it has inserted it. You should not use an autogenerated ID in PostgreSQL.
Instead, let Hibernate use a sequence generator and assign the ID to the entity before inserting it:
#SequenceGenerator(name = "FOO_SEQ", sequenceName = "FOO_SEQ")
public class Foo {
#Id
#GeneratedValue(generator = "FOO_SEQ")
#Column(name = "FOO_ID")
private Long id;

Related

Can Hibernate automatically select after insert?

I am inserting an object into a table using Hibernate saveOrUpdate(object). This object does have an automatically generated ID field and also a 'createdDate' field that is set by the database upon insert. After the insert, the ID field in the java object has the new generated value, but the 'createdDate' field is still null.
Is there a way (configuration or setting or parm) that can tell Hibernate to select the new row automatically after the insert is done, so that the Java object in memory is completely filled out? After the user 'saves' the object the webpage stays open on this object for the user to edit more fields (that are only available after the initial insert), so I want to show these generated fields ( ID, createdDate ) to the user.
** EDIT **
Due to an answer, I'm adding the HBM.XML file for the object:
<hibernate-mapping>
<class name="MyObject" table="MyObject">
<id name="objectId" type="java.lang.Integer">
<column name="Object_ID" />
<generator class="identity" />
</id>
. . . other attributes . . .
<property name="createdDate" type="timestamp" update="false" insert="false">
<column name="Created_Date" not-null="true" />
</property>
</class>
</hibernate-mapping>
Annotate the property with #Generated
#Generated(GenerationTime.INSERT)
private Date creationDate;
Note that this will have a cost. You could simply generate the creationDate in the code, and not in the database (using a listener or a JPA #PrePersist annotation).

hibernate one to one on foreign key

I have a main table that is D1 which has a unique id of d1Id. d1Id uniquely identifies the D1 records and is also a primary key on the table. I have table 2 which is D2 which has a d2seq as a primary key but D2 also has d1Id which is unique which has a foreign key constraint (I think) on D1. But I know for sure it's unique and the id's are the same. I am trying to retrieve d2 values when i make the D1 call using hibernate and i'm unable to get the right hbm for it as i'm getting compile time errors.
The bottom line of the issue is, I need to establish a one to one relationship between 2 tables where in the second table, the id which joins is not the primary key of the table. All the examples i've seen searching google have the case where the ID on the second table is also the primary key of the second table. Let me show you the HBM file I have right now.
<hibernate-mapping default-lazy="true"
package="com.xxx.xx.customer.dto">
<class name="D1" table="D1" dynamic-update="true">
<id name="dString" column="DID" type="java.lang.String"
unsaved-value="null" length="9">
<generator class="assigned"/>
</id>
...
<one-to-one name="d2" class="com.xxx.xx.customer.dto.D2" >
<!-- column name="d1Id" /-->
</one-to-one>
In my second hbm for D2, i'm stuck here
<hibernate-mapping default-lazy="true" package="com.xxx.xx.customer.dto">
<class name="D2" table="D2" dynamic-update="true">
<id name="id" column="D2ID" type="integer">
<generator class="native">
<param name="sequence">D2SEQ</param>
</generator>
</id>
<id name="d1id" column="D1ID" type="java.lang.String"
unsaved-value="null" length="9">
<generator class="assigned"/>
</id>
I obviously can't use the second id field for d1id here because 1> it's not a primary key and 2> i've already used it before. So how should my HBM files be for this operation?
Also once I have my HBMs in place, I would like to get D2 information while i query D1 through the DTOs. How can I do that?
Why can't you use #ManyToOne relationship? Often it provides more flexibility than #OneToOne

Mapping two tables 0..n in Hibernate

I have a table Users
CREATE TABLE "USERS" (
"ID" NUMBER NOT NULL ,
"LOGINNAME" VARCHAR2 (150) NOT NULL )
and I have a second table SpecialUsers. No UserId can occur twice in the SpecialUsers table, and only a small subset of the ids of users in the Users table are contained in the SpecialUsers table.
CREATE TABLE "SPECIALUSERS" (
"USERID" NUMBER NOT NULL,
CONSTRAINT "PK_SPECIALUSERS" PRIMARY KEY ("USERID") )
ALTER TABLE "SPECIALUSERS" ADD CONSTRAINT "FK_SPECIALUSERS_USERID" FOREIGN KEY ("USERID")
REFERENCES "USERS" ("ID")
/
Mapping the Users table in Hibernate works ok
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="USERS">
<id name="id" column="ID" type="java.lang.Long">
<meta attribute="use-in-tostring">true</meta>
<generator class="sequence">
<param name="sequence">SEQ_USERS_ID</param>
</generator>
</id>
<property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
<meta attribute="use-in-tostring">true</meta>
</property>
</class>
</hibernate-mapping>
But I'm struggling in creating the mapping for the SpecialUsers table. All the examples (e.g. in Hibernate documentation) in Internet I found don't have this type of self-reference. I tried a mapping like this:
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="SPECIALUSERS">
<id name="id" column="USERID">
<meta attribute="use-in-tostring">true</meta>
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<one-to-one name="user" class="User"/>
</class>
</hibernate-mapping>
but got the error
Invocation of init method failed; nested exception is org.hibernate.DuplicateMappingException:
Duplicate class/entity mapping com.initech.User
How should I map the SpecialUsers table? What I need on the application level is a list of the User objects contained in the SpecialUsers table.
How should I map the SpecialUsers table?
According to the structure of your USERS and SPECIALUSERS tables, you have a Table per subclass hierarchy and it is perfectly possible to map this kind of hierarchy with Hibernate.
First, make sure that SpecialUser inherits from User at the object model level (this is an inheritance relationship, not a self-reference).
public class SpecialUser extends User {
}
Then, declare a <joined-subclass> element in the User's mapping:
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="USERS">
<id name="id" column="ID" type="java.lang.Long">
<meta attribute="use-in-tostring">true</meta>
<generator class="sequence">
<param name="sequence">SEQ_USERS_ID</param>
</generator>
</id>
<property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
<meta attribute="use-in-tostring">true</meta>
</property>
<joined-subclass name="com.initech.SpecialUser" table="SPECIALUSERS">
<key column="USERID"/>
</joined-subclass>
</class>
</hibernate-mapping>
What I need on the application level is a list of the User objects contained in the SpecialUsers table.
The following HQL query would return all the SpecialUser (which are User too):
from SpecialUser
If later you need to add columns to the SPECIALUSERS table, add the corresponding attributes to the SpecialUser class and map them inside the <joined-subclass> element. Refer to the provided link (to the documentation) for the details.
If you really have to use a second table, you must map it to a new class. Hibernate can always only map one table to one class.
Alternatively, add a column to the user table which says "this user is special". If that is not an option, create a view which joins the two tables and thus simulates this column. Then, you can select users by this column.
If you go the two class way, you must load a list of the special users and do the mapping in your application.
[EDIT] Maybe you should look into parent-child relations. In your case, the user is the parent and its roles are the children. So every user has 0..n roles which are mapped in a different table. You can then use this HQL
from User u where :role in elements(u.roles)
to find all users with a certain role. But most of the time, you'll have a specific user and just need to query whether she has a certain role.

How to split a table's data into two sets based on a column value with Hibnernate mappings?

Suppose there are three tables:
Table A (ID, NAME)
Table B (ID, NAME)
Table A-B (A_ID, B_ID, Boolean_Property)
and Table A and B are modeled by classes A and B as follows:
public class A {
private long id;
private String name;
// All the B's that belong to A where the boolean property is True
Set<B> trueBSet;
// All the B's that belong to A where the boolean property is False
Set<B> falseBSet;
}
public class B {
private long id;
private String name;
}
How would I model this using Hibernate? I would like to be able to do the following, but it appears that discriminator column values don't exist for set attributes:
<class name="A" table="A">
<id name="id" column="ID">
<generator class="native" />
</id>
<property name="name" column="NAME" />
<set name="trueB" table="A-B">
<key column="A_ID"/>
<many-to-many column="B_ID" class="B"/>
<discriminator column="Boolean_Property" value="True" />
</set>
<set name="falseB" table="A-B">
<key column="A_ID"/>
<many-to-many column="B_ID" class="B"/>
<discriminator column="Boolean_Property" value="False" />
</set>
</class>
I think, you can apply where clause in set tag. Hibernate document state as follows in following link
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/collections.html
where (optional): specifies an arbitrary SQL WHERE condition that is used when retrieving or removing the collection. This is useful if the collection needs to contain only a subset of the available data.
as #ChssPly76 said this is a duplicate of
Multiple #ManyToMany sets from one join table
The solutions there suggest to use a view as Join-Column and plain SQL for CRUD operations.
This Answer is marked community wiki so if anyone else wants this question to leave the 'unanswered' section may freely upvote it.

Hibernate WrongClassException / Sets / Discriminators?

The problem looks like this:
A Product table. 3 joined-subclasses: DVD, CD, Book.
A Role table (composite id: NAME, ROLE, PRODUCT), and subclasses by discriminator column ROLE: actor, director, artist, author, etc.. which are mapped to Actor, Director, Artist, Author java classes; (pretty usual I guess) ...
A Book has authors, a CD artists, a DVD actors and directors - these are all modelled via set with a one-to-many relation pointing to the class of the items, e.g. Author, Director, Artist, etc.. which are just subclasses of Role (see 2.)
As long as a joined-subclass has only one such set (of people/roles), all works fine. But when it has two, like DVD, actors and directors, Hibernate throws a WrongClassException?
XML excerpt (Product.hbm.xml):
<joined-subclass name="media.DVD" table="V_DVD" lazy="false">
<key column="IDPRODUCT"/>
<property column="FORMAT" name="format" type="string"/>
...
<set name="actors" lazy="false">
<key column="IDPRODUCT"/>
<one-to-many class="media.DVD$Actor"/>
</set>
<set name="directors" lazy="false">
<key column="IDPRODUCT"/>
<one-to-many class="media.DVD$Director"/>
</set>
...
</joined-subclass>
XML (Person.hbm.xml):
<class name="media.Person" table="V_ROLE">
<composite-id>
<key-property column="NAME" name="name" type="string"/>
<key-property column="ROLE" name="role" type="string"/>
<key-many-to-one class="media.Product" column="IDPRODUCT"
name="product"/>
</composite-id>
<discriminator column="ROLE" insert="false" type="string"/>
<property name="name"/>
<property name="role"/>
<many-to-one class="media.Product" column="IDPRODUCT"
insert="false" name="product" update="false"/>
<subclass discriminator-value="author" name="media.Book$Author"/>
<subclass discriminator-value="artist" name="media.Music$Artist"/>
<subclass discriminator-value="creator" name="media.DVD$Creator"/>
<subclass discriminator-value="director" name="media.DVD$Director"/>
<subclass discriminator-value="actor" name="media.DVD$Actor"/>
</class>
It seems somewhat ok to me, yet it throws an exception.
Thank you for any idea!
I've got to say, this is a rather esoteric mapping. Why are you using a composite key (with discriminator being a part of it no less) instead of surrogate?
One possible issue here is you may be manually setting discriminator value (via role property) to something other than what it should be for given subclass. Hibernate won't be able to overwrite it (discriminator is mapped with insert="false") and this would cause a WrongClassException on subsequent select.
It's also possible that there' something funky going on in the Product mapping from which media.DVD extends and which you didn't include. Can you add that as well as provide full stack trace?
The problem is basically that your model is not normalized: You tell hibernate that there is a composite key, but you use only part of that key to reference the table.
I think you can implement this by either having a set of people in your product and each person has a role, or by mapping each set to a separate (linking) table with your person table.
Another more esoteric approach would be to map to a MultiMap: In fact you have a Map<Role, Set<Person>> in your product. Hibernate does not support this out of the box, but I once wrote a UserType for this.
Cheers,
-Maarten

Categories

Resources