views:

98

answers:

5

Hi, I've problem with Hibernate.

I have a class User

class User { 
 int id;
 String name;
}

where id is native generator in User.hbm.xml , and name is primary-key in DB.

In my database , I saved some information about Users.

Than, I want to connect with this information about User.

For example in my DB i have row INSERT INTO User VALUES ('Bill');

Main.java

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);

This code always trying insert bill to database , rather than update when row about Bill exists in DB...

Could you help me ?

Thank you for advance.

+2  A: 

So, Id is not saved in the database ?

Why is Id not the primary key in de DB, if you map it in Hibernate as being the identifier ?

Why haven't you just put a unique constraint on 'Name' in the database, and create a Primary Key constraint on Id ?

Frederik Gheysels
Thx for your rely.`id` is primary key and `name` has unique constriantWe have object class User for instance :`User bill = new User()` and attributes about bill we get from keybord or website , and my question is:How can you make saveOrUpdate() meaning if bill.name exists in db we call update() else we save bill.
kunkanwan
A: 

You should use session.update(object) while you are updating, and session.save(object) while you are saving

stista
And `saveOrUpdate()` can do that for you, which is the point of this method...
Pascal Thivent
Yeah , you are right but I want function saveOrUpdate() from hibernate would do the work for me. I could write my saveOrUpdate() where i check in select if `name` exists in db and call save() or update(). I think it's not good idea , and maybe hibernate has better solution for example override equals() where we compare element from bussines key.
kunkanwan
+2  A: 

This code always trying insert bill to database , rather than update when row about Bill exists in DB...

From the section 10.7. Automatic state detection of the Hibernate core documentation:

saveOrUpdate() does the following:

  • if the object is already persistent in this session, do nothing
  • if another object associated with the session has the same identifier, throw an exception
  • if the object has no identifier property, save() it
  • if the object's identifier has the value assigned to a newly instantiated object, save() it
  • if the object is versioned by a <version> or <timestamp>, and the version property value is the same value assigned to a newly instantiated object, save() it
  • otherwise update() the object

When you do:

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);

This newly created instance does not have any identifier value assigned and saveOrUpdate() will save() it, as documented. If this is not what you want, make the name the primary key.

Pascal Thivent
Thx for your rely , I see why my program always trying insert. How can I do that without making name the primary key because I have id which is faster and easier. I can do it using extra select like that: `User bill = new User(); bill.setName("Bill"); bill.setId(func());` where func() is a function which result is null when row with `name='Bill'` doesn't exists otherwise return id number this row; How can I do that without select ? How solve this problem Pro Developer ?
kunkanwan
@kunkanwan: I'm not sure how I should understand this "pro developer". Right now, this doesn't motivate me to help you further.
Pascal Thivent
@Pascal Thivent: I'm afraid you don't understand me. My english is poor. In sentence 'Pro developer' I want know how solve this in software industry( I'm student without experience) where my simple function with extra select is not enough good. I'm sorry if I hurt you.
kunkanwan
@kunkanwan Ok, no problem then. I'll come back on this question tomorrow.
Pascal Thivent
A: 

So you want:

User u1 = new User("Bill");
session.save(u1);
User u2 = new User("Bill");
session.saveOrUpdate(u2);

to notice that u1 and u2 are the same Bill and only store it once? Hibernate has no way of knowing that the Bills are the same person. It only looks at the id of User u2, sees that it's not set, concludes that u2 should be inserted, tries that and reports an exception.

SaveOrUpdate persists both a completely new object and a loaded object that's currently attached to the session. So this works (assuming you have a findByName method somewhere and there's another attribute, let's say favoriteColor):

User u1 = new User("Bill");
u1.setFavoriteColor("blue");
session.saveOrUpdate(u1);
User u2 = findByName("Joe");
u2.setFavoriteColor("red");
session.saveOrUpdate(u2);

But that's not what you want, right?

Your problem is made worse by your entity having a surrogate primary key and, separately, a business key (enforced via a uniqueness constraint). If you didn't have an id field and only name as primary key, you could use merge() (for a discussion of saveOrUpdate vs merge, look here):

User u1 = new User("Bill");
u1.setFavoriteColor("blue");
session.save(u1);
User u2 = new User("Bill");
u2.setFavoriteColor("red");
u2 = session.merge(u2);

But you don't have that, you need to enforce both the PK constraint on id and the uniqueness on name. So you'll need some variation of merge that does that. Very roughly, you'd like something along these lines:

public User mergeByName(User user) {
    User merged;
    User candidate = findByName(user.getName());
    if (candidate != null) {
        user.setId(candidate.getId());
        merged = session.merge(user);
    } else {
        session.save(user);
        merged = user;
    }
    return merged;
}
wallenborn
A: 

First question: If you need to fetch a user named "Bill". How would you do that? That should give you an idea.

To update, you need to have an identity associated with the user object. Having just the name attribute set is not going to help. If you want to update regardless without having the identifier, use HQL as query.

Query query = session.createQuery("update User u set u.name = :newName where u.name=:name");
query.setString("name", "Bill");
query.setString("newName", "John");
query.executeUpdate();
Kartik