views:

1014

answers:

2

I have a user object that has a one-to-many relationship with String types. I believe they are simple mappings. The types table hold the associated user_id and variable type names, with a primary key 'id' that is basically a counter.

<class name="Users" table="users">
    <id column="id" name="id" />
    ...
    <set name="types" table="types" cascade="save-update">
        <key column="id" />
        <one-to-many class="Types" />
    </set>
</class>

<class name="Types" table="types">
    <id column="id" name="id" />
    <property column="user_id" name="user_id" type="integer" />
    <property column="type" name="type" type="string" />
</class>

This is the java I used for adding to the database:

User u = new User();
u.setId(user_id);
...
Collection<Types> t = new HashSet<Types>();
t.add(new Type(auto_incremented_id, user_id, type_name));
u.setTypes(t);

getHibernateTemplate().saveOrUpdate(u);

When I run it, it gives this error:

61468 [http-8080-3] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1062, SQLState: 23000
61468 [http-8080-3] ERROR org.hibernate.util.JDBCExceptionReporter - Duplicate entry '6' for key 'PRIMARY'
61468 [http-8080-3] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update

When I check the sql, it shows:

Hibernate: insert into users (name, id) values (?, ?)
Hibernate: insert into types (user_id, type, id) values (?, ?, ?)
Hibernate: update types set id=? where id=?
  • Why does Hibernate try to update the types' id?

The error says: Duplicate entry '6' for key 'PRIMARY', but there really isn't? I made sure the ids are incremented each time. And the users and types are added into the database correctly.

I logged the information going in, and the types added has an id of 7 and a user id of 6. Could it be that Hibernate takes the user_id of 6 and tried to update types and set id=6 where id=7? Therefore the duplicate primary key error?

But why would it do something so strange? Is there a way to stop it from updating?

  • Should I set the id manually? If not, then how should I add the types? It gives other errors when I add a type object that only has a type string in it and no ids.

Thanks guys. Been mulling over it for days...

+1  A: 

Your biggest problem is incorrect column in the <key> mapping - it should be "user_id", not "id". That said, your whole mapping seems a bit strange to me.

First of all, if you want IDs auto generated you should really let Hibernate take care of that by specifying appropriate generator:

 <id column="id" name="id">
   <generator class="native"/>
 </id>

Read Hibernate Documentation on generators for various available options.

Secondly, if all you need is a set of string types, consider re-mapping them into a collection of elements rather than one-to-many relationship:

 <set name="types" table="types">
    <key column="user_id"/>
    <element column="type" type="string"/>
 </set> 

That way you won't need explicit "Types" class or mapping for it. Even if you do want to have additional attributes on "Types", you can still map it as component rather than entity.

Finally, if "Types" must be an entity due to some requirement you have not described, the relationship between "Users" and "Types" is bi-directional and needs to be mapped as such:

 <set name="types" table="types" inverse="true">
    <key column="user_id"/>
    <one-to-many class="Types"/>
 </set>

 ...
 in Types mapping:
 <many-to-one name="user" column="user_id" not-null="true"/>

In the latter case "Types" would have to have a "user" property of type "Users". Here is a detailed example.

ChssPly76
Stuck with collection of elements! Thanks!
April
A: 

The solution that worked for me was to separately save the two parts (without adding type to user):

getHibernateTemplate().save(user);
getHibernateTemplate().save(new Type(user.id, type_name));

And with the < generator class="native" /> on only the types id.

Bad practice?

Had mapped it as a collection of elements, but it was somewhat wrongly adding the user_id to the types id column which causes duplicate error sometimes; since types id is the only primary key column. Weird! I sort of remember there was some other column error, but forgot about it, because I immediately reverted back to one-to-many. Couldn't grasp the strange workings of Hibernate...

I will try the bi-directional solution sometime... Thanks a lot for all the help :)

April
I'm afraid you're missing the point completely. You should be letting Hibernate make your life easier, not fight with it every step of the way - and having correct mappings would go a long way toward achieving that. Scenario you've described above is very basic; there are plenty of examples available (I've posted links in my answer). You really do need to read through documentation, get this working and understand _how_ it works; otherwise it'll get a lot harder down the road.
ChssPly76
Yes I know it's very basic, so I'm confused why it still breaks. Using this solution, hibernate tries to search types by matching type id to user_id which is completely weird.So I did the collection of elements mentioned above, and am having class cast error now.Making the mappings for Hibernate makes life so difficult! Every time there is a mapping, they don't follow up with a way how the objects can be accessed or retrieved. You have to search and dig around some other place.
April