-->
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.  [ 10 posts ] 
Author Message
 Post subject: How are you validating your entities
PostPosted: Thu May 31, 2007 1:24 pm 
Beginner
Beginner

Joined: Wed Nov 29, 2006 12:23 pm
Posts: 42
given that my last question didn't bring much comment

(http://forum.hibernate.org/viewtopic.php?t=975158)

I thought I'd ask a bit more of a general question.

How are you validating your entities before saving them?

I realise that this question doesn't relate directly to NHibernate, but it does relate to where/how to implement functionality in an architecture/framework that's making use of NHibernate.

Given the general lack of discussion of NHibernate, I get a feeling that no one really uses a generalised validation implementation, and may be relying on front end validation to ensure that their data is valid.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 31, 2007 5:02 pm 
Regular
Regular

Joined: Sun Jan 21, 2007 4:33 pm
Posts: 65
I validate my entities through the AMS.Textbox library. Since my application is used by one induvidual currently, I have no need to worry about multiple users or outside users injecting code.

However, if I had to worry about such things, I suppose I would just have a standard regular expression that I'd pass my entities through (for example, no Phone number could have letters; Social must be 9 numbers, 2 dashes (that were preferably automatically placed), and whatnot).


Top
 Profile  
 
 Post subject: Re: How are you validating your entities
PostPosted: Fri Jun 01, 2007 7:50 am 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
hitch wrote:
Given the general lack of discussion of NHibernate, I get a feeling that no one really uses a generalised validation implementation, and may be relying on front end validation to ensure that their data is valid.


My personal belief on this topic is that you should never let your objects get into an inconsistent or non-savable state. This means that I would never allow a business object to have an invalid phone number. If my rule is that there are no alphabetic characters in a phone number then I will have a SetPhoneNumber method which makes sure of it. I'll leave out the basic setter on the property where typically people would just bind the textboxes in the front end.

I know this flies in the face of what a lot of people believe. Many people just want data binding support and want a framework to make everything easy for them. I suppose I used to think of things this way, but when I really got in to OR/M tools I completely changed my mind.

Its my belief that an OR/M tool is not a persistence tool but instead of a synchronization tool. An OR/M is a tool which manages entities. To me an object in memory is no different than an object in my database and vice versa. To me the OR/M has stabilized my memory and given me much more of it at the price of performance (relative to all data being stored in memory).

As such I don't believe I should ever have to care if an object is in the database or not. It's just an object within my domain. I have free access too all objects in my design, regardless of if it is through an object graph or using some query that happens to search for objects (it could search memory, a database whatever).

Now given all that I just want whatever is in memory to be able to be synchronized with my data store, I want to make sure my objects in memory never get into a state where they can not be synchronized. I suppose this isn't a 100% rule, but it is the general principle.

That being said I do believe it is the job of the UI to check for type constraints. Things like ensuring that a textbox which is only supposed to take integers, only does take integers. That isn't the job of a business object. Instead the business object should just expose an integer type if the correlated field should only be integers.

So in the end with my approach, you don't really need a validation methodology since every method has to be able to validate itself before assigning values.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 01, 2007 8:24 am 
Beginner
Beginner

Joined: Wed Nov 29, 2006 12:23 pm
Posts: 42
Thanks for the response jchapman. with the Set[property]() method approach, how do you report errors in this case? Do your set methods throw exceptions, or do you have a means of collating errors so a single collection of all errors is reported at once?

Quote:
That being said I do believe it is the job of the UI to check for type constraints


The problem I have is that my business layer is only accessed through a webservice, which at this stage is used by 2 front ends, and in future maybe more. Therefore ensuring the validation is carried out appropriately by the front end is out of my control, and i have to have validation implemented in my business layer/entity model.

Thanks again - something to think about...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 01, 2007 8:36 am 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
hitch wrote:
Thanks for the response jchapman. with the Set[property]() method approach, how do you report errors in this case? Do your set methods throw exceptions, or do you have a means of collating errors so a single collection of all errors is reported at once?[\quote]

This was actually the topic of a lot of discussions in my team. Many people didn't want to along with my approach at first. Basically every method returns what I deemed an IResult. It's just a structure which indicates successful execution of the method or not. This really says "did anything happen?". In addition to the result we return different type of messages. The result contains a list of informational, warning and error messages. We automatically set the result of the method based on the existence or lack of error messages. If there exists an error message we say the method failed. If there are no error messages we say it was successful. We then support a hierarchy of messages where one warning may have many detail messages to it. There may have been 3 failure messages at the root with each failure having sub messages describing in detail why it happened. We then use message codes instead of text to describe what happened so that we could pull the text for the message from a resource file (to support multiple languages).

Now this is only for business failures. Any error which is deemed to be a programmer mistake throws exceptions. If we expect an error to be caused based on business reasons, messages are returned, if it is truly unexpected we consider it exceptional.

We then have a control for the front end which displays IResults to the user indicating everything which happened (successful results or error results).

So basically when you enter a method, check all of the preconditions (which can get complicated) before assigning anything. If we fail any preconditions don't perform the operations. If we check preconditions and it says successful, but then while performing an operation we encounter an error we throw exceptions since our preconditions should have caught it and it truly is exceptional at that point. Therefore our objects never get in to a state where they can not be persisted/synchronized.

hitch wrote:
The problem I have is that my business layer is only accessed through a webservice, which at this stage is used by 2 front ends, and in future maybe more. Therefore ensuring the validation is carried out appropriately by the front end is out of my control, and i have to have validation implemented in my business layer/entity model.

Thanks again - something to think about...


Well, understand what I was saying here. I'm saying we'll have a method which takes in an integer, such as SetPriorityLevel(int) (Not a real method of course). If there is a priority text box on the UI then they make sure they get an integer and pass it to us. We don't expose a SetPriorityLevel(string) or SetPriorityLevel(object) which would try to convert it to an integer and then process it. So we rely on the UI to tell the user "You must enter an integer value for the priority" or the like. We won't handle that as part of our results. By exposing your web service I assume you can enforce that you are passed an integer for priority?

If the rule is that the priority must be between 3 and 5, then we'll check that in the business object. When you call the method we would check it up front and then return a result stating what the issue was if you entered 2.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 01, 2007 8:51 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
There are some interesting posts between Udi and Ayende on validation that make make valuable reading: http://udidahan.weblogs.us/category/validation/

Cheers,

Symon.


Top
 Profile  
 
 Post subject: Re: How are you validating your entities
PostPosted: Fri Jun 01, 2007 9:29 am 
Newbie

Joined: Thu May 03, 2007 2:30 am
Posts: 18
jchapman wrote:
hitch wrote:
Given the general lack of discussion of NHibernate, I get a feeling that no one really uses a generalised validation implementation, and may be relying on front end validation to ensure that their data is valid.


My personal belief on this topic is that you should never let your objects get into an inconsistent or non-savable state. This means that I would never allow a business object to have an invalid phone number. If my rule is that there are no alphabetic characters in a phone number then I will have a SetPhoneNumber method which makes sure of it. I'll leave out the basic setter on the property where typically people would just bind the textboxes in the front end.

I know this flies in the face of what a lot of people believe. Many people just want data binding support and want a framework to make everything easy for them. I suppose I used to think of things this way, but when I really got in to OR/M tools I completely changed my mind.

Its my belief that an OR/M tool is not a persistence tool but instead of a synchronization tool. An OR/M is a tool which manages entities. To me an object in memory is no different than an object in my database and vice versa. To me the OR/M has stabilized my memory and given me much more of it at the price of performance (relative to all data being stored in memory).

As such I don't believe I should ever have to care if an object is in the database or not. It's just an object within my domain. I have free access too all objects in my design, regardless of if it is through an object graph or using some query that happens to search for objects (it could search memory, a database whatever).

Now given all that I just want whatever is in memory to be able to be synchronized with my data store, I want to make sure my objects in memory never get into a state where they can not be synchronized. I suppose this isn't a 100% rule, but it is the general principle.

That being said I do believe it is the job of the UI to check for type constraints. Things like ensuring that a textbox which is only supposed to take integers, only does take integers. That isn't the job of a business object. Instead the business object should just expose an integer type if the correlated field should only be integers.

So in the end with my approach, you don't really need a validation methodology since every method has to be able to validate itself before assigning values.


Hello....

I belong to the "other" crowd... I think you should "allow" invalid data inside your BO, but your BO must be able to let the GUI know that it is in an invalid state. If you inform the GUI on whats requiered for a new Person to be valid, then you are coupling the GUI very tightly to the BO and you will have a very hard time to get databinding to work.

How about a "Person" object, and a mandatory LastName propperty?

If you create a new Person, you MUST Supply a Name... So by your rule you cannot do "new Person()" since that would lead to an object in an invalid state.

If the Object knows itself that a LastName is requiered, then you can prevent the saving of the object. So my Objects support an IsValid property, and to save an object you dont call session.Save(obj), but obj.update() (So the Object can throw an exception if the save fails, or is not possible due to broken constrains)


Top
 Profile  
 
 Post subject: Re: How are you validating your entities
PostPosted: Fri Jun 01, 2007 10:15 am 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
rdrunner wrote:

Hello....

I belong to the "other" crowd... I think you should "allow" invalid data inside your BO, but your BO must be able to let the GUI know that it is in an invalid state. If you inform the GUI on whats requiered for a new Person to be valid, then you are coupling the GUI very tightly to the BO and you will have a very hard time to get databinding to work.


Bi-directional databinding is made more difficult, absolutely. I'm fine with that condition, I don't mind writing a few extra lines on my UI to call methods instead of using an automated bidirectional databinding.

That being said another approach would be to use DTOs which are created by your BOs and accepted by your BOs. You could then use those methods there to tell if you entered invalid values. So in other words transient objects which are never persisted can be in invalid states, but not persistent business objects.

rdrunner wrote:
How about a "Person" object, and a mandatory LastName propperty?

If you create a new Person, you MUST Supply a Name... So by your rule you cannot do "new Person()" since that would lead to an object in an invalid state.


Yup, you got it, accept a name in the constructor or factory.

rdrunner wrote:
If the Object knows itself that a LastName is requiered, then you can prevent the saving of the object. So my Objects support an IsValid property, and to save an object you dont call session.Save(obj), but obj.update() (So the Object can throw an exception if the save fails, or is not possible due to broken constrains)


So what if you loaded an object from the data store, changed the last name to be blank and then flushed? Maybe you check in other methods as well and throw exceptions? Does that even work? If the session stays open every flush will try to perform this operation. You need to clear out the session after a failure like this. What if at flush only some objects are invalid? Does everything get rolled back? Must it be in a transaction? How do you handle this? Saving a single object is relatively simple, but complex operations can become, well complex.

I certainly don't want to trust UI code to verify the state of the object. Then I need to get into issues with my NHibernate code. But I don't want my business object to know it uses NHibernate. Therefore the only way to verify that the business object is valid when it is saved, is to have it ensure it is always valid.

Plus what if you set the last name to blank then call another method? What does that method do? Objects in invalid states can cause lots of downstream problems with methods that may be called prior to saving or updating.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 02, 2007 1:19 pm 
Regular
Regular

Joined: Wed Apr 25, 2007 4:18 am
Posts: 51
Location: Belarus, Gomel
Hi jchapman!

What about concurency and uniquiness - how can you check it inside BO or even whole domain?
There ara a lot of things you can't check, so you will have "invalid" objects in memory - they will raise exception during session flush and you have no means to avoid it... So your attempts to minimize possibility of devastating NH exception (after which all you can do is restart application or affected module, or perform brain-sick session and BO restoration :( )

_________________
WBR, Igor


Top
 Profile  
 
 Post subject: Re: How are you validating your entities
PostPosted: Mon Jun 04, 2007 3:58 am 
Newbie

Joined: Thu May 03, 2007 2:30 am
Posts: 18
jchapman wrote:
Bi-directional databinding is made more difficult, absolutely. I'm fine with that condition, I don't mind writing a few extra lines on my UI to call methods instead of using an automated bidirectional databinding.

That being said another approach would be to use DTOs which are created by your BOs and accepted by your BOs. You could then use those methods there to tell if you entered invalid values. So in other words transient objects which are never persisted can be in invalid states, but not persistent business objects.


Hello... I am actually going the way you describe here... But the DTOs are NOT used to make Databinding work, but to persist my Objects into the DB. So my flow of data is actually DB->DTO->BO->Gui. A session will be create for every "request" and each request by itself is a transaction. You are only able to Call the Update() method on a root object. So you cannot persist the adress itself, without saving the custumer.

jchapman wrote:
Yup, you got it, accept a name in the constructor or factory.


Again this will make Databinding "harder" ;)

jchapman wrote:
So what if you loaded an object from the data store, changed the last name to be blank and then flushed? Maybe you check in other methods as well and throw exceptions? Does that even work? If the session stays open every flush will try to perform this operation. You need to clear out the session after a failure like this. What if at flush only some objects are invalid? Does everything get rolled back? Must it be in a transaction? How do you handle this? Saving a single object is relatively simple, but complex operations can become, well complex.

I certainly don't want to trust UI code to verify the state of the object. Then I need to get into issues with my NHibernate code. But I don't want my business object to know it uses NHibernate. Therefore the only way to verify that the business object is valid when it is saved, is to have it ensure it is always valid.


This is solved by a very strict seperation of the layers of the application. The UI code does not have access to the session. The only way to create a session is to call the update method on my object itself. This will pass the object to the application server, where it will be persosted. If the object is in fact invalid, then it will throw an exception. A parent will check all its children to determine if it is valid. So there is no way to get an invalid object into the DB.

Also the code for the verification of this state are not saved into the UI. They belong to the object itself. So we can have an UI that will be quite dumb, since it only needs to check if the object is valid in order to save it.


I hope this makes sense so far... ;)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 

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.