I'm using lazy property in the object.
1) I need to load object without that property, detach it from the session.
2) Then I need to reattach this object to newly created session and load that property.
So, I am fetching data from the database (1) :
return session
.CreateCriteria<DataResource>()
.List<DataResource>()
.ToArray();
Than I'm trying to reattach it and fulfill (2):
using (ISession session = GetSessionFactory().OpenSession())
{
session.Update(dataResource);
NHibernateUtil.Initialize(dataResource.Value);
}
In case if laziness was on one-to-many link - all works ok. (1) step returns my real object, with a proxy set to that property, and after (2) step it become real object.
But in case when I need laziness on the property, it seems that NHibernate cannot handle that with real object. Instead of that it returns proxy after step (1). Than in the step (2) it throw MappingException: No persister for: Castle.Proxies.DataResourceProxy on the .Update() line. Somehow it cannot recognise its own proxy.
You can unproxy the object before detach from the session.
To unproxy see the link
NHibernate Get objects without proxy
Related
I'm relatively new to NHibernate and I've got a question about it.
I use this code snippet in my MVC project in Controller's method:
MyClass entity = new MyClass
{
Foo = "bar"
};
_myRepository.Save(entity);
....
entity.Foo = "bar2";
_myRepository.Save(entity);
The first time entity saved in database succesfully. But the second time not a single request doesnt go to database. My method save in repository just does:
public void Save(T entity)
{
_session.SaveOrUpdate(entity);
}
What should I do to be able to save and then update this entity during one request? If I add _session.Flush(); after saving entity to database it works, but I'm not sure, if it's the right thing to do.
Thanks
This is the expected behavior.
Changes are only saved on Flush
Flush may be called explicitly or implicitly (see 9.6. Flush)
When using an identity generator (not recommended), inserts are sent immediately, because that's the only way to return the ID.
you should be using transactions.
a couple of good sources: here and here.
also, summer of nHibernate is how I first started with nHibernate. it's a very good resource for learning the basics.
I've a problem of session when I use lazy loading in the UI layer.
My piece of code (in the DAO layer)
public List<Visites> GetVisitesClientQuery(string idClient)
{
using (ISession session = Repository.TSession())
{
var results = (from v in session.Query<Visites>()
where v.Clients.Idclient == idClient
select v);
return results.ToList<Visites>();
}
}
I call it in the UI layer :
var visites = VisiteManager.Instance.GetVisitesClientQuery(lstClients.SelectedValue.ToString());
foreach (Visites v in visites)
{
foreach (Factures f in v.Factures)
{
...
}
}
v.Factures is a collection.
If I call it in the using it works (the session is opened) but in this case it doesn't work and I've this error.
Initializing[NHibernateTest.BusinessObjects.Visites#036000007935]-
failed to lazily initialize a collection of role:
NHibernateTest.BusinessObjects.Visites.Factures, no session or session was closed
Is it possible to handle a lazy loading call in the UI layer ?
The problem here, is that you handle your session management inside your repository (DAO layer), which isn't a good idea.
An ISession implementation in NHibernate represents a 'Unit Of Work'. A Unit Of Work needs to know the 'context' of the 'use-case' to be able to use this concept successfully.
Your repository however has no notion of the 'context' of the use case in which it (the repository) is used.
Therefore, it is not your DAO layer that should decide when to open an ISession, but it is your 'application layer' (or even your UI layer, if you do not have an Application Layer) which should do that , since that will be the layer that knows your context.
By doing so, you can indeed effectively use the Session as a UnitofWork. In order to save an entity, you'll have to use the same session to save the entity, as the session that you've used to load that entity. (Otherwise, you'll need to 'lock' the entity into the session).
Next to that, it will also solve your lazy loading problem. :)
You should eager load the collections you know you will be using with
session.Query().Fetch(x=>x.Factures).
That will load all Visites with the Factures.
I have the following code:
public class A
{
private ISessionFactory _sf;
A(ISessionFactory sf)
{
_sf = sf;
}
public void SomeFunc()
{
using (var session = _sf.OpenSession())
using (var transaction = session.BeginTransaction())
{
// query for a object
// change its properties
// save the object
transaction.commit();
}
}
}
Its used as follows in a unit test
_session.CreateCriteria ... // some setting up values for this test
var objectA = new A(_sessionFactory);
objectA.SomeFunc();
// _session.Clear();
var someVal = _session.CreateCriteria ... // retrieve value from db to
//check if it was set to the
//proper value
//it uses a restriction on a property
//and a uniqueresult to get the object.
//it doesnt use get or load.
Assert.That(someVal, Is.EqualTo(someOtherValue)); // this is false as long
//as the _session.Clear() is commented.
//If uncommented, the test passes
I am testing against a sqlite file database. In my tests I make some changes to the db to setup it up properly. I then call SomeFunc(). It makes the required modifications. Once I am back in my test, the session however doesnt get the updated values. It still returns the value as was before calling SomeFunc(). I have to execute _session.Clear() to have the changes reflect in my assertion in the test.
Why is this needed?
Edit: cache.use_second_level_cache and cache.use_query_cache are both set to false
Edit2: Read the following statements in the NH Documentation.
From time to time the ISession will
execute the SQL statements needed to
synchronize the ADO.NET connection's
state with the state of objects held
in memory. This process, flush, occurs
by default at the following points
* from some invocations of Find() or Enumerable()
* from NHibernate.ITransaction.Commit()
* from ISession.Flush()
And in section 10.1 it says,
Ensure you understand the semantics of
Flush(). Flushing synchronizes the
persistent store with in-memory
changes but not vice-versa.
So, how do I get the in memory objects to get updated? I understand that objects are cached per session. But executing a UniqueResult() or a List() should sync with the db and invalidate the cache, right?
What I cannot understand is why is the session reporting stale data?
It depens on what king of operations do you make. NHibernate has first level cache by default. It uses cache to get entities by ID and so on.
The in memory view of objects (the level 1 cache) is per session.
A takes an ISessionFactory and opens its own session with its own transaction scope.
Even if the contents of the ISession used in SomeFunc are flushed to the database, _session will not see those changes until its level 1 cache is cleared.
You have two sessions. One is in A.SomeFunc, and the other is in your unit test. Each session has it's own instance of the entities in the session-cache (1st level cache). The sessions do not communicate or coordinate with each other. When one session writes its changes, the other session isn't notified. It still has it's own outdated instance in its session cache.
When you call _session.Clear(), you make the session "forget" everything by clearing the session cache. When you re-query, you are reading fresh data from the database, which includes the changes from the other session.
We are trying to use NHibernate 1.1 to as the persistence layer behind a web service API. Nothing new there. We use Automapper to translate the domain objects we get from (Fluent-)NHibernate to DTO's which we send over the wire.
The problem we are seeing is the following scenario:
We read an object from the repository
We translate that object (via Automapper) into the DTO form.
After some, perhaps trivial fiddling, the object is mapped back from DTO to the Fluent-Nhibernate object (including the primary key which cannot change).
We save the object.
After step 4 we get a Nonuniqueobjectexception from NHibernate and it creates a new row to save the object (with a new primary key). We want to update the original row but instead, new rows get modified(!)
So, in this situation, how can we convince NHibernate to do an actual update instead of an insert operation?
BTW, if we skip the translation to the DTO and back, there is no problem with the update.
== Tevya ==
1) NHibernate 1.1 or Fluent NHib 1.1?
2) I think you have a session management problem. If you load one object in session1 and try to persist it without attaching the actual object to session2 you will end up with a new row in the DB. Try to read and update the object within one session and see the results.
You could try merging the object into your session.
// Assuming you already have a session open
// and you've already mapped your DTO back
using (var tx = session.BeginTransaction())
{
var nhibernateObject = (YourNhibernateObjectType)session.Merge(mappedBackFromDTO);
tx.Commit();
}
You should attach your (new) object after mapping from DTO to the current ISession. Attaching is the operation made by ISession.Update method.
This question is a bit of a dupe, but I still don't understand the best way to handle flushing.
I am migrating an existing code base, which contains a lot of code like the following:
private void btnSave_Click()
{
SaveForm();
ReloadList();
}
private void SaveForm()
{
var foo = FooRepository.Get(_editingFooId);
foo.Name = txtName.Text;
FooRepository.Save(foo);
}
private void ReloadList()
{
fooRepeater.DataSource = FooRepository.LoadAll();
fooRepeater.DataBind();
}
Now that I am changing the FooRepository to Nhibernate, what should I use for the FooRepository.Save method? Should the FooRepository always flush the session when the entity is saved?
I'm not sure if I understand your question, but here is what I think:
Think in "putting objects to the session" instead of "getting and storing data". NH will store all new and changed objects in the session without any special call to it.
Consider this scenarios:
Data change:
Get data from the database with any query. The entities are now in the NH session
Change entities by just changing property values
Commit the transaction. Changes are flushed and stored to the database.
Create a new object:
Call a constructor to create a new object
Store it to the database by calling "Save". It is in the session now.
You still can change the object after Save
Commit the changes. The latest state will be stored to the database.
If you work with detached entities, you also need Update or SaveOrUpdate to put detached entities to the session.
Of course you can configure NH to behave differently. But it works best if you follow this default behaviour.
It doesn't matter whether or not you explicitly flush the session between modifying a Foo entity and loading all Foos from the repository. NHibernate is smart enough to auto-flush itself if you have made changes in the session that may affect the results of the query you are trying to run.
Ideally I try to use one session per "unit of work". This means one cohesive piece of work which may involve several smaller steps. If you feel that you do not have a seam in your architecture where you can achieve this, then managing the session inside the repository will also work. Just be aware that you are missing out on some of the power that NHibernate provides you.
I'd vote up Stefan Moser's answer if I could - I'm still getting to grips with Nh myself but I think it's nice to be able to write code like this:
private void SaveForm()
{
using (var unitofwork = UnitOfWork.Start())
{
var foo = FooRepository.Get(_editingFooId);
var bar = BarRepository.Get(_barId);
foo.Name = txtName.Text;
bar.SomeOtherProperty = txtBlah.Text;
FooRepository.Save(foo);
BarRepository.Save(bar);
UnitOfWork.CommitChanges();
}
}
so this way either the whole action succeeds or it fails and rolls back, keeping flushing/transaction management outside of the Repositories.