-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Surrogate keys and business identity
PostPosted: Fri Jan 02, 2004 2:17 pm 
Beginner
Beginner

Joined: Sun Dec 21, 2003 11:19 pm
Posts: 22
Location: Kentucky, USA
I agree with the direction of Hibernate and the manuals that stress the use of surrogate keys for tables. This simplifies RI and makes more sense than relying on the "unchangeable" business attributes. I am looking for ideas on how others handle the requirements for uniqueness of business attributes.

Example:
A course at a college has a number that is unique within a department and a description
    Math 101 Introduction to Calculas
    English 101 The Plays of Shakespeare
A typical schema for this would be
    id long
    dept char(25)
    coursenum char(3)
    description char(50)
    primarykey (id)
    unique index (dept, coursenum)

The four approaches I see are:
1) Handle Hibernate Exceptions when the Course object is saved and the unique index constraint is violated.
2) Intercept the save, check for duplicate values and throw an application specific exception.
3) Implement business logic in the Course setters to check for duplicates and throw an application specific exception
4) #3 with either 1 or 2

Pros (+) /cons (-)
#1
+ Minimizes additional code
+ Smallest performance impact on majority of updates (no constraint violation)
- Late notification to end users
- If saved with dependent objects (Teachers, Students, Sections), will cause all work to be unsaved.
? will Hibernate identify the reason for the failure in an consistent / easy manner
#2
+ Flexiblility of coded solution, i.e. can be as complex as needed
- Some code but essentially boilerplate (might be able to implement pattern to refactor)
- would probably require a query to the table in the middle of an update
#3
+ Flexiblility of coded solution, i.e. can be as complex as needed
+ Quicker notification to user
+ Makes domain object more responsible for correct behavior
- Additional code
- Does not guarantee data integrity will not be violated outside the app
- May require more queries against the db to get list of current courses
- May still be possible to have constraint violation if 2 users insert the same record at the same time (dirty read vs committed read)
#4
+ quick notification
+ ensures data integrity will not be violated outside the app
- most code

Anyone have additional solutions, pros/cons or see something that I missed? How do you handle similar requirements in your applications? If you use multiple approaches, what criteria do you use to determine the best approach?

Thanks for taking the time to read my post!
Timothy Vogel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 02, 2004 2:24 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
I usually tend to go with 1 and 3 in combination, as this allows to generate very early feedback in the application when illegal unique constraints are entered. As I do mostly rich-client desktop application work, I find it more convenient for the user to get feedback allready during data entry, in contrast to doing all his work and then pressing save and get an error. I won't go with only 3 however, as this is really to unsafe for me :)

The really problematic thing with 1 is that in my experience you can't really tell in a portable way if the HibernateException you catch comes from a unique constraint violation or some other, real error. Anyone has found a good solution for this, or am I seeing problems where none exist?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 02, 2004 3:06 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
If the violation is 'expected' business speaking, I use 3+1.
If violation should and won't happen I do 1.

I always let my DB keep integrity rules.

Quote:
The really problematic thing with 1 is that in my experience you can't really tell in a portable way if the HibernateException you catch comes from a unique constraint violation or some other, real error. Anyone has found a good solution for this, or am I seeing problems where none exist?

I'm interested too...

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 02, 2004 7:27 pm 
Beginner
Beginner

Joined: Sun Dec 21, 2003 11:19 pm
Posts: 22
Location: Kentucky, USA
Thanks for the replies and confirmation that I am headed down a "well travelled path"!

I'm still at the design stage with no real code written so I may be checking back with some implementation questions.

Anyone else have an opinion? Any takers on how to detect unique constraint violations in a portable way ?

Thanks again for your time!
Timothy Vogel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 12:48 pm 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
I am in the third case where unicity have for me business meaning. You say that in this case you put the check in the setter. I am not agree with that because one course do not know anything about other courses. Thus apart if your BO know something about Hibernate you don't have any way to check the unicity of your course num. As mentionned by emmanuel in the thread http://forum.hibernate.org/viewtopic.php?t=926855 it is better if your BO know nothing about persistence.
I personally think of two other possible places where to put your check :
- In the CourseDAO. The problem is when to check for it. If you do the check every time you ask the DAO to save the course you do it too often (sometimes you do no modify the coursenum when you modify the course)
- In the service/process layer. In this case it is up to the developer that uses your Course object to check for that : it is not his job.
In conclusion I cannot find a suitable place to put this check : does anybody have an idea ?

seb


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 12:54 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
I am all for doing it in the dao. If you can't stand the additional querys, you will have to implement some dirty checking sceme. Or provide two dao methods, one that checks and the other that does not. You still get an HibernateException if someone usses the unchecking one, which is now rather a RuntimeException.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:24 pm 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
Ok but apart from the performance problem there is another problem that seems to be specific to Hibernate.
My DAO have something like a getById method that do a load. I call this method from my service layer inside a transaction and I do a setCourseNumber after that. Then, when my transaction commits my modification is written in my db. It is possible to modify a BO without calling the modify method on the DAO !
I see two possible solutions for this problem but I don"t know if there is one possible :
1 - Do something in the getById method of my DAO to prevent that. Maybe I have to evict the object from my session or not to use the hibernate load method : it seems pretty ugly, isn't it ?
2 - Implement an hibernate specific interface in my DAO that allows me to know when there is a modification of my object. Then test if the course number is modified and check for uniqueness : it is very hibernate dependant and seems uglier than the previous solution.

Is there other solutions ?

seb


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:30 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Validate interface ?

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:34 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Oh yes, I did not think of that, automatic dirty checking makes the things really interesting. :)

Possible solution: Disassociate the object from the session before returning it by getById somehow - by manual evict()? This will keep automatic dirty checking from working and require an explicit call to a DAO method to store the update.

If you keep the object associated with the session, and somebody calls setCourseNumber without calling the DAO store method afterwards you will have a problem (programmer error) -> throw a RuntimeException on transaction commit after the HibernateException is thrown (because of unique constraint violation)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:37 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Quote:
Validate interface ?


Yes, thats nice too, but requires to modify the buisness objects, and you need once again to include DAO-Specific code in the validate method ... [/quote]


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:37 pm 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
emmanuel wrote:
Validate interface ?


Can you explain a little bit more your "validate interface" ?

I am convinced that the best way is too but my uniqueness check in my create/update method of my DAO. What disturb me is the behaviour of the load. Why is it possible to modify an object without calling update ? Is there a way not to do that ?
If I want my DAO to be notified of a save or update of the BO associated with it, do I have to implement an interceptor ?

seb


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:40 pm 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
gloeglm wrote:
If you keep the object associated with the session, and somebody calls setCourseNumber without calling the DAO store method afterwards you will have a problem (programmer error) -> throw a RuntimeException on transaction commit after the HibernateException is thrown (because of unique constraint violation)

If the user enter a value that violate the constraint but in the other case the value change in db. It can lead to very tricky bugs because you modify a value from a place you are not supposed to.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:41 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
See Validatable JavaDoc for the Validateable interface.

The behaviour you notice is automatic dirty checking. See my previous post for ideas for solutions.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:42 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
scesbron wrote:
gloeglm wrote:
If you keep the object associated with the session, and somebody calls setCourseNumber without calling the DAO store method afterwards you will have a problem (programmer error) -> throw a RuntimeException on transaction commit after the HibernateException is thrown (because of unique constraint violation)

If the user enter a value that violate the constraint but in the other case the value change in db. It can lead to very tricky bugs because you modify a value from a place you are not supposed to.


Well, you should allways keep all your data integrity constraints in the DB too, because otherwise you will most likely run into a lot of trouble anyways (concurrency, multithreading, whatever)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2004 1:50 pm 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
gloeglm wrote:
scesbron wrote:
gloeglm wrote:
If you keep the object associated with the session, and somebody calls setCourseNumber without calling the DAO store method afterwards you will have a problem (programmer error) -> throw a RuntimeException on transaction commit after the HibernateException is thrown (because of unique constraint violation)

If the user enter a value that violate the constraint but in the other case the value change in db. It can lead to very tricky bugs because you modify a value from a place you are not supposed to.


Well, you should allways keep all your data integrity constraints in the DB too, because otherwise you will most likely run into a lot of trouble anyways (concurrency, multithreading, whatever)


Yes I am agree with you, I do not want to suppress the db constraints.
I am jsut asking about a possible problem of the behaviour of the load method. If a method in the service layer just get an object by id and call a setter on this object, I do not think this will change the value in the db. So you can have a bug of a value changed where you don't want it to.
It seems that it would be much better to evict the object from the session when I load it but in this case :
1 - Does this have any side effects ?
2 - Why this is not the default behaviour of the load method ?
I feel that I miss something because for me the load method leads to a weird behaviour


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.