Using fluent NHibernate I have a property on a class mapped using Version
Version(x => x.Version);
When I save the object, the Version property gets incremented in the database as I would expect, but the value of the property on the object only seems to change sometimes.
using (var tx = session.BeginTransaction())
{
session.Merge(item);
tx.Commit();
item.Version; // Sometimes this is still 1, when I expect it to be 2.
}
The problem is then that if it remains as 1 and I make more changes and save again I get a StaleObjectStateException.
What's weird is that sometimes it works fine and the item.Version value does get correctly incremented, but I can't figure out the difference between the cases where it does and the cases where it doesn't.
I've tried searching but can't seem to find any documentation on this. Can anyone explain what NHibernates expected behaviour is with the Version mapping?
[NHibernate version 2.1.2]
From the ISession.Merge documentation:
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session.
So, it will not modify item.
(I might add I have never used Merge in my apps. You might want to review how you are dealing with attached and detached entities)
Did you try
item = session.Merge(item);
tx.Commit();
?
You need to flush the session before the updated version will propagate up to your entities. Unless you flush the session, you are responsible for keeping the entities up to date yourself.
You should TYPICALLY let the session flush on its own when its closed. However, in some instances where you rely on database updates that happen via nhibernate and not settings you make to the entity itself, you might need to flush the session yourself after a commit. In this case be aware that when you flush the session ANY entities that are dirty will be committed. This may not be desirable so be sure that the scope is very limited.
Related
I have problem with cache in Fluent NHibernate. I want to disable it for query by ID e.g.
session.Get<Person>(10);
Do you have any ideas ?
Are you referring to the first-level (session) cache?
You can refresh the state of an entity from the database by using Refresh, that is:
// Will get the state from the first-level cache if already present in the session:
var entity = Session.Get<EntityType>(entityId);
// Line below will update the entity with the current state from the database:
Session.Refresh(entity);
If you already hold the entity, call directly session.Refresh(person) on it instead of getting it again.
You may also evict it with session.Evict(person), causing it to no more be in the session, and no more tracked for changes either. Then discard it and eventually get it again later if you need.
Otherwise, this is unusual to consider it is a trouble getting it from the session cache. This is frequently a sign of bad session usage, such as using a same session across many user interactions (anti-pattern).
You can still do what Fredy proposes. Or call session.Clear() before getting for clearing the session cache (and losing all pending changes by the way).
Instead of a Person object that is mapped you could create a DTO for Person and do a QueryOver().
The PersonDTO object wont be cached in Nhibernates first-lvl-cache.
I´m using NHibernate to data access Layer.
I have an entity in memory previously loaded, and Im making changes in order to save after on database. The problem comes when my application is running in some machines at the same time, and other user has deleted from database the same object that I have in memory and I want to save. When I try save the changes or delete this entity, a StaleStateException in fired.
I check if an entity exists on database calling session.Get<T> of this way (it´s get a null succesfully):
using (var session = NHibernateSessionHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var entity = session.Get<T>(persistObject.Id);
return entity == null ? false : true;
}
}
The problem comes when I can´t differentiate between when the entity has been deleted by other session/user (therefore my entity in memory is obsolete) or the entity has been recently created and is able to save.
I think that the unique solution is implement a mechanism to check if the entity has already been saved or loaded from database, in order to discard the entity or save when proceed.
Is there a way to check this behaviour by using nhibernate? Im tried with session.Refresh() and session.Get<T> but I still without know if the object is new and ready to save or obsolete.
Help very appreciated.
The situaltion you have is a tipical error handling one. Because a user have dicided to delete an object in your database and an other user want save a change to the same object you can't say what the right state should be. The user is the one who should dicide what to do with situation. You can make your error handling smarter by giving him some chooses. For situations where you have multiple users which write to the same object you should also implement a meganism like optimistic locking to prevent an other user to override a change which he did not see. If you have many of these situation you should think about redesign your db/object structure to edit less data at once or rethink the work/processes your users do with the system.
The question is about Doctrine but I think that can be extended to many ORM's.
Detach:
An entity is detached from an EntityManager and thus no longer managed
by invoking the EntityManager#detach($entity) method on it or by
cascading the detach operation to it. Changes made to the detached
entity, if any (including removal of the entity), will not be
synchronized to the database after the entity has been detached.
Merge:
Merging entities refers to the merging of (usually detached) entities
into the context of an EntityManager so that they become managed
again. To merge the state of an entity into an EntityManager use the
EntityManager#merge($entity) method. The state of the passed entity
will be merged into a managed copy of this entity and this copy will
subsequently be returned.
I understand (almost) how this works, but the question is: why one would need detaching/merging entitiies? Can you give me an example/scenario when these two operations can be used/needed?
When should I Detaching an entity?
Detaching an entity from the an EM (EntityManager) is widely used when you deal with more than one EM and avoid concurrency conflicts, for example:
$user= $em->find('models\User', 1);
$user->setName('Foo');
// You can not remove this user,
// because it still attached to the first Entity Manager
$em2->remove($user);
$em2->flush();
You can not take control of $user object by $em2 because its session belongs to $em that initially load the $user from database. Them how to solve the problem above? You need to detaching the object from the original $em first:
$user= $em->find('models\User', 1);
$user->setName('Foo');
$em->detach($user);
$em2->remove($user);
$em2->flush();
When should I use merging function?
Basically when you want to update an entity:
$user= $em->find('models\User', 1);
$user->setName('Foo');
$em->merge($user);
$em->flush();
The EM will make a compare between the $user in database vs the $user in memory. Once the EM recognize the changed fields, it only updates them and keeps the old ones.
The flush method triggers a commit and the user name will updated in the database
You would need to detach an entity when dealing with issues of concurrency.
Suppose you are using an asynchronous API that makes callbacks to your project. When you issue the API call along with callback instruction, you might still be managing the entity that is affected by the callback, and therefore overwrite the changes made by the callback.
You can also detach entity when you have pernamently data in your database, but in your code you modify this entities depending on the user account.
For example browser game which have some characters and some attacks to fight. AttackOne used by "UserFoo" (lvl 90) will be modified by better bonuses than used by "UserBarr" (lvl 20), but in our database AttackOne all the time is the same attack
I'm quite new to nHibernate, so this'll probably be a pretty stupid question. But anyway, saving an object works fine, updating it doesn't work.
This is what I'm doing:
using (ISession session = _sessionFactory.OpenSession())
{
session.SaveOrUpdate(schemaChange);
schemaChange.ScriptName = "New one";
session.SaveOrUpdate(schemaChange);
}
The first SaveOrUpdate inserts a schemaChange in the database. The second one should update the same object, but nHibernate doesn't do that.
In the output I get:
DEBUG - persistent instance of: DotNetMigrations.Core.Domain.SchemaChange
DEBUG - ignoring persistent instance
DEBUG - object already associated with session: [DotNetMigrations.Core.Domain.SchemaChange#129]
UPDATE
Well, as it was so simple (and a stupid question), I found it myself:
session.SaveOrUpdate(schemaChange);
schemaChange.ScriptName = "New one";
session.Flush();
Makes sence. nHibernate is really superior to any orm tool I've worked with.
What I can't seem to figure out is why there's a SaveOrUpdate method... If you're updating, then isn't the object automatically already associated with the session? (because you got it out of the db in the first way. Unless off course you sent it to for example a Flex RIA and it came back)
So, how do you know if the object is already associated, to either do a SaveOrUpdate() or just a Flush()?
You can use the Method Session.Contains(object) to figure this out.
The difference between Save() and Update() is that Save assigns an Id if necessary, wheather Update() fails if the object has no key or the Key does not exist in database.
SaveOrUpdate fixes some issues regarding working with transient objects, if you don't care what the state of the object is you may call it, but isn't the holy grail at all.
If you know what state the object has i would suggest to call the exact method.
Hopefully this helps a little bit to clarify.
What is the difference between SaveOrUpdate and Save/Update in NHibernate. Why wouldnt you just always use SaveOrUpdate? Also, what is the point of SaveOrUpdateCopy?
Chapter 9 covers all of this better than I can:
http://nhibernate.info/doc/nh/en/index.html
But cliff notes:
Save() takes a new object without an identifier and attaches it to the session. The object will be INSERT'd.
Update() takes an existing object that has an identifier but is not in the session and attaches it to the session. The object will be UPDATE'd.
SaveOrUpdate() looks at the identifier and decides what is necessary in the above.
SaveOrUpdateCopy() is special in that say you have two objects with the same identifier -- one in the session and one not. If you try and update the one not in the session an exception is thrown normally (you are now trying to attach two objects that represent the same persistent object to the session). SaveOrUpdateCopy() copies the non-session object state to the session object state.
I'm not sure how you are going to use NH, but for a lot of cases all you need is Save(). The session is doing ALL of the work necessary to know what has to be updated and simply Flush() or a Commit() does everything you need.