NHibernate - problems with validation and transactions - nhibernate

I'm using NHibernate as my ORM. I have a situation where I have some stuff wrapped in an ITransaction. I am listening to the SaveUpdate event in NHibernate and then doing my entity validation in that SaveUpdate handler.
For one of my entities, I want to validate that the value of a certain property hasn't changed. So I figured that I would load up the value of the existing object from the database and compare it with the new value. The problem is that I called ITransaction.Commit() to save my entity object and the transaction hasn't actually been committed at the time that validation occurs, so I can't load the existing object from the database because the transaction has it locked.
So I guess I have a few different questions here:
- Is the SaveUpdate event the correct place to do validation?
- Is there another way I can do this so that I can do the validation that I need to do (getting the existing value from the database and comparing)?
I'm sure someone else out there has run into a similar situation...... hopefully!

If you want to see an example of how to do validation, I suggest checking out ScottGu's NerdDinner. Although he's using Linq to SQL for his ORM, it's very easy to adapt it to NHibernate.
I recently used a validation system similar to the NerdDinner one in an ASP.NET MVC + NHibernate project with great success.

Validation has nothing to do with persistence, so saveupdate is not the right place. The correct place of validation depends on: what you want to validate, your programming style, the UI framework you use to show the validation messages, etc. Personally, I prefer to put the validation on the place where things are changed, so I would put it in the change method that sets the property. I don't understand why you want to load the entity in the previous state, because that state is already loaded when you load it for the first time.

Related

Debugging Self Tracking Entities - AcceptChanges exception due to object's key values conflict with another object in the ObjectStateManager

I have an exception occurring when saving changes to a self tracking entity:
AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
I believe the problem is addressed in other questions such as: Self Tracking Entities - AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager
My question is what is the best way to debug this problem both in development and production. Is there any further information that can be caught/accessed which will detail which entities or the entity types which are causing the exception.
If not will I have to write something to traverse the object graph looking for duplicate keys referencing different objects? If so does anyone have experience of this?
Further info:
My scenario involves the following - the client retrieves an entity via a WCF service which contains collections of further entities all with various FKs to other entities. These FK relationships are all included in the linq query so we have a complete object graph.
The views in the client use previously fetched entities for static data such as lookup tables for performance. If we have say a Customer object with a FK to User this will be loaded when retrieved from the service. If we now add another entity to the object graph e.g. Order and set a User property on this object which has the same Id as in the Customer object but the entity was retrieved at a different point and therefore using a different ObjectContext (i.e. the objects have the same Id but are not the same instance of the object) I get this error.
The link to the other question demonstrates ways to avoid this but I am looking to find more information about which entities are causing the problem so I can track down the error.
This usually happens if you try to AcceptChanges on the context which was used to load entities before - use new empty context for accepting changes. AcceptChanges cannot be used when any entity from STE is already loaded in the context - that is limitation of current STE implementation (but it can probably be removed if you rewrite the template).
As I know there are no detailed exceptions for this kind of problems. For debugging STEs check their generated code. You have whole STE code available so you can browse change tracker and search for entities but it will not be easy.
I'm actually not sure if it is even possible to define duplicates on the client but let's suppose that it is. If you have the control over client code the best way is diagnose the client code. Add some logging and find the reason for duplications. Then remove the duplication because fixing the issue on the client will be easier then fixing the issue on the service. If you don't have control over the client I would say that it is a problem of incorrect data passed to your client and let client's developers to fix it.
I had been banging my head against this problem for more hours than I cared to admit. Finally found that the cause of the problem was that I had listened to the ReSharper hint to make my
context provider static. since that occurred with a variety of other changes, I didn't think to check it as being the culprit. But in my case, that was the issue.

Saving objects in EntityFramework over WCF causes related entities to be created

A couple of times on this current project developers have hit the same problem:
An object with related entities, i.e. an Order with a related Customer is sent back via WCF to entitywork to be saved. If the object is new we use AddObject() to put it back in the context and if it has changed, then we use ApplyCurrentValues() to update the object.
The Order object has changed, but the Customer object has not (unless the streaming via WCF affects it in some way). However, when calling SaveChanges() on the context the main object, Order in this example, is saved, but a new copy of Customer is also added to the database.
The workaround that we have found is to set the reference to Customer on Order to null before calling SaveChanges(), however this feels like a bit of a kludge.
What I'm looking for is the "correct" way to solve this problem, something akin to LazySaving = false, i.e. only save the object changed and don't try to create all the related objects.
Thanks in advance for any pointers.
I am not sure about Entity Framework, but I ran into this issue recently with NHibernate. I solved it by implementing save as follows
(1) Retrieve original entity from DB
(2) Update original entity from WCF Data Transfer object using AutoMapper
(3) Save original entity
I am not sure if you are trying to use your entities as DataContracts, in my experience its always better to use Data Transfer Objects rather than entities as you DataContract. If you dont, you continually run into all kinds of trouble, and DTO+AutoMapper gives you the control to solve most issues that you run into
http://automapper.codeplex.com/

Implement own IsDirty in nHibernate

For my current project, we use a nHibernate session to retrieve the object, and another session to update the changes we've made to the object in between the two session. If we use SaveOrUpdate(), nHibernate will typically do a select-then-update (so, two calls to the database).
However, our own business objects already keep track of changes. So, we'd ideally want to intercept within nHibernate and vote whether the object has been changed or not (without letting nHibernate do the select-statement).
Would that be possible with an interceptor?
You can use your own custom Persister.
Check this - https://www.hibernate.org/161.html
with the interceptor you can intercept all querys and change then or add some sql to
don't now if you can stop nhibernate for doing a select query

NHibernate Rollback w/ broken rules (validation best practice)

I'm working on a legacy system that is using the enterprise library validation block to add a broken rule when an object is not valid. Then the user is returned a message based on this error and told the object was not updated.
The only issue is that now I'm using NHibernate to persist these objects -NHProf shows an update to the object when I commit the session. This is because the object has been modified I assume and the ORM is simply doing its job.
My question is this - what would be the best way to check for these broken rules before I commit the session? Or should I not use Enterprise library and switch to something NHibernate friendly?
Update
I came across this event listener class for the NHibernate Validator Event Listener - my final implementation was very similar
I'm not familiar with the enterprise validation block, but can't you write an interceptor or something like that which can be used to determine whether the object can be saved or not, based on the information you have regarding the broken rules ?
You can also choose not to use the automatic dirty checking of NHibernate.
This means that you'll have to call 'Save' yourself on an object you have modified in order to get that object saved.
You can get this functionality via NH Addins

Using NHibernate to determine which fields have been updated (for validation purposes) before persisting

Prior to persisting updates to my business entities, I need to perform validation checks to determine which properties have been changed. For example, certain fields can only be updated when the "Status" property has a particular value. E.g. when an Order entity has a Status of finalized, only the notes (string) field can be updated. Is this sort of thing possible using NHibernate, or should I be tracking the changes myself in the Business entities?
If I understand what you're trying to do, Gabriel's solution is not quite what you need. If it is not, you can try an event listener. Those allow you to hook into a common event (like on save) and do some processing before NHibernate finishes the save/insert/update/delete. Alternatively, you could look into using interceptors by implementing the IInterceptor interface.
This sort of thing is indeed possible. Coding Instinct has a great post introducing NHibernate.Validator.