New Posts New Posts RSS Feed: Validation Question
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Validation Question

 Post Reply Post Reply
Author
mcalhoun View Drop Down
Newbie
Newbie


Joined: 18-Apr-2010
Location: Marlboro, NJ
Posts: 5
Post Options Post Options   Quote mcalhoun Quote  Post ReplyReply Direct Link To This Post Topic: Validation Question
    Posted: 26-May-2010 at 1:40pm
I have an Entity (OrderOwner) that has a compound key (OrderId, OwnerId, OwnerTypeId). In Silverlight, I am newing up an OrderOwner object in the ViewModel, setting the OrderId and then binding comboboxes in XAML for Owner and OwnerType.
 
The problem I am getting is that when the user selects a OrderId/Owner/OwnerType combination that already exists in the DB, a System.InvalidOperationException (Message=An entity with this key: OrderOwner: db4d6dc3-2b6a-44fd-bdd0-24d4c81284bc,b2ced23c-2b00-479e-b5a1-00ebfcb39a4d,e469f4e0-d66c-4d3d-992b-3aa05ecdb7ec already exists in this EntityManager) is being thrown.
 
Because of the two-way binding, this exception is being thrown before the user actually hits the "Save" button, so I can't do Instance verification to see if the object exists before saving. Is there a way I could use BeforeSet to make sure the combination doesn't exist prior to allowing the property to be changed? If so, can someone point me in the right direction as I haven't worked with BeforeSet before.
 
Thanks,
Matt
Back to Top
ting View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 27-Mar-2009
Location: San Francisco
Posts: 427
Post Options Post Options   Quote ting Quote  Post ReplyReply Direct Link To This Post Posted: 26-May-2010 at 8:58pm
Whoa.  For this and many other reasons, it's not a good idea to bind the UI to the key of an entity.  At a minimum, I would collect the information you need from the user beforehand, verify that it is correct, and then call a new on the OrderOwner with the valid parameters.
 
If you have control over the schema, it would also be a good idea to designate a single column primary key for the table instead of using a compound key, which will improve performance and make the management of rows in that table easier in the future.
 
For completeness, if you tried to use BeforeSet to "solve" the problem, you would immediately run into issues because you need to perform an asynchronous database query for a validation that has to return synchronously.  Even if that were solved (let's say using WPF instead of Silverlight), you would still be invoking a database query for every value change on the combox which would introduce latency (especially when using the keyboard to scroll through the list of values).  Then there's the issue of usability as the user tries to set the three values correctly, but some intermediate states may be invalid, and you're validating on each value change.  I'm sounding a bit harsh, but we feel this is really not a good practice even if it were possible.
 
If you want more help, describe your workflow/logic for this process, and and we can come up with some suggestions.
 
Back to Top
mcalhoun View Drop Down
Newbie
Newbie


Joined: 18-Apr-2010
Location: Marlboro, NJ
Posts: 5
Post Options Post Options   Quote mcalhoun Quote  Post ReplyReply Direct Link To This Post Posted: 27-May-2010 at 6:41am

Ting,

Thank you for your reply. The approach I've taken with all objects is to create a new object and then bind to the UI because of the immediate validation feedback we get as a result. This approach seems to work very well when the key is not bound as you said.
 
My confusion is on your two other suggestions. If I create a new single-column primary-key, how do I ensure that the Order/Owner/Type combination is unique before saving to the db? Also, by "gathering the information, then creating the object" as you suggest, I loose the validation that comes along with the entity "for free" when databound to the UI, correct? For instance, the Silverlight UI would no longer alert when the user didn't select an owner and hit save, I would have to handle that in my code, correct? I just want to make sure I'm not missing something. We have several of these "join" tables in the application and I want to work out an efficient pattern for them prior to continuing their implementation.
 
Thanks,
Matt
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 01-Jun-2010 at 8:51pm
All is much easier if you can change to an arbitrary primary key (e.g, a counter or a Guid).
 
We understand that the other three fields must form a unique combination in the database. You won't be able to save the entity until they are jointly unique. You can check the database at anytime. You can check when the user changes any of these values (by making an asynchronous query of the database). You can wait until save ... where you may have to fail the save attempt and ask the user to fix the problem.
 
Only you know whether it is wiser to determine availability up front or can afford to check later.
 
If you cannot change the primary key, you'll have to do some kind of validation up front.
 
The second approach - "gathering the information, then creating the entity" - could be interpreted in two ways.
 
A) Create an entire UI-oriented entity surrogate (aka ViewModel) which the user modifies; then validate the combo-ID before creating the real entity and populating it with the values the user entered into the ViewModel/Surrogate.
 
B) Create a separate object to gather just the three fields that comprise the ID. Evalute this. Once it passes, create the entity, set its ID with the approved three field values, and edit the new entity much as you would an existing entity.
 
You seem to be thinking about (A) in which case you are correct about the consequences. Were you to write such a ViewModel you would have to map to all of the entity properties, port all validation logic to the ViewModel and reimplement INotifyPropertyChanged and all the goodness baked into the DevForce entity.
 
Ting is suggesting (B). You first coax the user into settling the issue of ID uniqueness. Once that is out of the way then ... and only then ... do you create the new entity, giving it the approved three-value ID.
 
This way, once ID unquess is resolved, you can bind to the created OrderOwner entity and benefit from that entity's built-in validation and other behavior.
 
We are imagining that you might present an "Add OrderOwner" dialog that asks for the three critical pieces of information. This dialog binds to a much simpler ViewModel (e.g., one having just the three properties). The "OK" button results in an asynchronous query to verify that combination is available. You'll use the BusyControl to "freeze" the UI (block user input) until the answer returns.
 
You get the idea we hope; you relegate the problem to a dialog that concentrates exclusively on the unique-ID problem.
 
[You must also check to see if the combination Id is in cache. You could make the cache check your only check at this time.
 
The user wouldn't have to wait for the server to return the answer. The downside is that you may be unable to save the entity later because that Id, while not in cache, has already been registered in the database.  Of course that is a potential problem even with the suggested design ... because someone could slip in a new record with that Id between the time you checked and the time you save. Only you know the probabilities.]
 
Approach (B) makes life easier on you. Will it be good for the user? That's something you have to figure out. I'd be reluctant to take the easy (B) path if that made the user suffer. I'd suck it up and do (A).
 
---
 
It occurs to me that you might be able to implement either (A) or (B) using an OrderOwner entity instead of having to write a wrapping ViewModel.
 
The duplicate primary key problem doesn't manifest itself until you add it to the target EntityManager.
 
I'm thinking out loud here so bear with me.
 
You could create another EntityManager that is only used for adding new OrderOwner entities. When the user presses the "Add" button, you create a new OrderOwner ... in this "TempEntityManager".  You still have to force the user to make the ID unique (at least locally). You can let the user fill in some of the other properties if you think that is a good idea (I cringe).
 
Once ID uniqueness is established (which means confirming that this ID is not in the real EntityManager ... as well as not currently in the database) ... you detach it from TempEntityManager and add it to the real EntityManager. The entity retains "object entity" which means that the UI continues to reference the same CLR object. You've just moved the object from one EntityManager to another.
 
It's a hack ... but it should work. It's less complicated if TempEntityManager is only allowed to hold a single OrderOwner. Let the user add one new OrderOwner, resolve the unique ID issue, then detach and add the new OrderOwner to the "real" EntityManager.
 
We hope one of these ideas yields a breakthrough for you. 
 
P.S.: PLEASE say that the combination key cannot change once the OrderOwner has been entered into the database. If this is NOT true, you are in big trouble ... especially if related entities refer to this entity by its three-part-key. Do whatever you can to switch to a single, synthetic (arbitrary, meaningless) key and use that for all FK references. You can still insist that the three fields are jointly unique. Just make sure their values are only to be found in the OrderOwner entity.
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down