I have this situation: I'm developing a software with Spring.net and Fluent NHibernate, and I noticed something very unusual with NHibernate's behavior. I really don't know whether it's correct or not, but for my software it cannot happen. I noticed that NHibernate is calling twice all the getters, even when I'm updating something on the database. For exemple, when I try to insert some values on dabatase, NHibernate gets the value from the property to put on database, and then it triggers a new get again, which I don't know why and how is called. I think it tries to retrieve the value from cache to compare both values (database and cache) and save the updated value on cache.
By the way, for some entities I have a secondary cache level, but this situation happens with entities that have and don't have this secondaty cache level.
Any help? Thank you.
You should be able to find it out using print of current stack track
in particular getter and compare it to other traces. This should
show you starting point.
What get into my mind:
Backward get for caching because of second level cache as it stores properties of entities only.
What about has-code computing? Is it use properties to or fields?
Verification whether object in session is as same in the database.
If with get you mean NHibernate runs a select on the database to retrieve the object, within an insert/update this will be done only if you provide the ID of the object and the object is not already available within the session.
If you don't have the object in the database and want NHibernate to insert a new one, do not provide an ID and configure the generator of your ID map correctly
Otherwise make clever use of proxies and prevent NHibernate to retrieve the full object by using Load<T> which will not actually hit the database but puts a proxy into the current session scope.
Related
I still have difficulties with some NHibernate terms so please bear with me.
I am building a POCO class based off a web submission. The web user will be changing some scalar properties. The POCO will already be persisted in the database. I want to save changes to the POCO to the database, collect the child objects (which should be unchanged) and return the POCO's graph so I can send feedback back to the user.
What is the proper way to do this? Is this "detached"? What is the appropriate method for connecting the child collection? Can it be done in one database batch?
Persisting changes to your object is easily done using Session.Update().
retrieving child collection is done either implicitly (by accessing the collection property which causes nHibernate to fetch it from the DB), or explicitly, using the Fetch() method.
For example- var users = QueryOver<User>().Where(u => u.Age > 18).Fetch(u => u.Children).Eager.
In general, for a web app, I would recommend reading a little about the 'session per request' pattern. (this example is a little bit of an overkill for my taste, but it explains the concept quite well).
Also don't forget to always use transactions.
Is there anyway to implement in-memory or fixed/hardcoded object instances in NHibernate that appear to all intents and purposes to be real instances of the object read from the database?
I have a historical database that has a number of missing foreign key values against a number of different tables as they are fixed/hard coded in the old DAL.
This is causing me problems in my NHibernate mapping.
An example of this would be a fixed immutable user, say 'ADMIN' that exists in code but not in the database. This 'ADMIN' user is still used in various foreign keys so needs to exist in NHibernate so that it can manage the FK mapping.
I've managed cheat loading by using a sql view which has the hard coded rows explicitly added, but of course I can't write to a view like that so need an alternative solution.
I did find a reference to the uNhAddIns WellKnowInstanceType that seems to do something similar, but I couldn't get to to work.
Anyone have any alternative suggestions?
one trick i can think of is attaching the imaginary User instance to the session befor querying using sess.Lock(admin, LockMode.None); that should take care of the reference. But I#m not sure what happens when eager loading the reference.
Im making .net application as a project on my Univeristy and I have a problem with Self-Tracking Entity Sets. I'm selecting an record, passing it through a wcf service, make some changes and pass it to the server again. There I want to compare what was changed, so Im selecting the same record from context once a again (this is the record with old values) and comparing. Then, after comparing I want to call ApplyChanges on context with entity passed via the service, and Im getting an error:
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 suppose it's because loading the same entity twice (before changes and after changes to compare). Is there any better way to compare changes(I need to make change history in another db table)? And wouldnt this error also apear if two clients gets the same record, and the first one changes it and wants to store into db? Im using .net 4.0.
This is not supposed way to use STEs. STEs wrap a lot of logic but they are not able to handle duplicate keys attached to context.
So I can imagine two solutions:
Do not load entity for comparing changes. Instead apply changes from your STE and handle SavingChanges event (or override SaveChanges on context) to get applied changes from ObjectStateManager.
Try to detach loaded entity before you apply changes from STE.
I'm using Fluent NHibernate and the setup I have is as follows:
An Address object, which is a simple list of address fields.
A Company object which has two references to address objects, MainAddress, InvoiceAddress.
The problem I'm having is that on occasion both MainAddress and InvoiceAddress may refer to the same record in the Address table.
Addresses are looked up by searching, using something along the lines of:
ICriteria c = session.CreateCriteria(typeof(Address))
.Add(Example.Create(address).ExcludeNone());
Because each Address is selected seperately, this leads to two instances of the same record, which causes NHibernate to puke when trying to save the Company object.
"a different object with the same identifier value was already associated with the session"
What's the best way to work around this?
Thanks!
Unless you are selecting in different sessions and then mixing them (which is incorrect), NHibernate's default behavior is to retrieve the same instance for the same row, no matter how many times you query.
Make sure you're using a single session.
You should use NHibernate's Merge.
merge():
if there is a persistent instance with the same identifier currently
associated with the session, copy the
state of the given object onto the
persistent instance
if there is no persistent instance currently associated with the session,
try to load it from the database, or
create a new persistent instance
the persistent instance is returned
the given instance does not become associated with the session, it
remains detached
It's the same as SaveOrUpdateCopy, but that command's apparently deprecated:
I think SaveOrUpdateCopy is something
that has exited in NHibernate for all
time and Merge is something added in
2.1 (clearly something ported from the hibernate). Anyway I am very glad that
NHibernate has this ability because
writing and handling the merge
operation manually is very boring code
to write!
When using Session.SaveOrUpdate(myEntity); how does NHibernate decide how whether to insert a new record or update an existing one?
I am having trouble whilst saving one object in a S#arp project. It is retrieved from storage, then stored in session state for a couple of web requests, then saved back to the database with one property changed (not the S#arp [DomainSignature]).
I have, at runtime, compared the object that is about to be persisted with a freshly retrieved version straight from the database using the Equals() method and that returns true. However, the object still ends up creating a new row in the database.
Elsewhere in the application this is working fine but I am hoping for a pointer on how NHib is working this out.
Basically SaveOrUpdate() is looking for an identifier. If the identifier is present, it will update the record in the database. If the identifier is not present, it will create a new record.
However, it sounds like you might have something funky going on in your session. You might want to try SaveOrUpdateCopy() to see if this solves your issue.