Pass a Guid to NHibernate's ISession.Get<T> method - nhibernate

I'm experiencing with NHibernate 3.1.0 (without Fluent yet) on an existing solution in VS2010. Our DB is MsSql 2008 (I'm using NHibernate.Dialect.MsSql2008Dialect in the cfg.xml file).
I have an ValidationActivity object which I'd like to get from the DB. It has an ActivityID column of type uniqueidentifier (in the DB) / Guid (in the business object).
I've been following Summer Of NHibernate's 1st session so my provider is:
public ValidationActivity GetActivityById(Guid activityGuid)
{
var sessionFactory = new configuration().Configure().BuildSessionFactory();
var session = sessionFactory.OpenSession();
return session.Get<ValidationActivity>(activityGuid);
}
My mapping uses the guid generator:
<id name="ActivityID" type="Guid">
<generator class ="guid"/>
</id>
To test that, I created a test that tries to get an activity with a known Guid (one that I've inserted manually) as follows:
NHibernateDataProvider provider = new NHibernateDataProvider();
Guid guid = new Guid("885f380d-c6e3-459e-8cff-10f96f26cc0a");
Activity testActivity = provider.GetActivityById(guid);
The exception thrown is 'Could not load entity' with the following SQL string:
SELECT validation0_.ActivityID as ActivityID0_0_, validation0_.ActivityName as Activity2_0_0_, validation0_.CreationDate as Creation3_0_0_, validation0_.Owner as Owner0_0_, validation0_.Project as Project0_0_, validation0_.Step as Step0_0_ FROM Activities validation0_ WHERE validation0_.ActivityID=?
It seems to me that the '?' at the end is wrong, but I don't know what am I doing wrong.
Please help.
Thanks.

Take a look at this post with a similar problem:
Mapping Error in NHibernate
Have you tried to run the query above replacing the ? with the actual guid in the database that this test is hitting? Are all the column/table names the same? Seems like it could be a mapping issue.

Related

How to save and then update same class instance during one request with NHibernate?

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.

NHibernate ISession.Save() - Why is this persisting my entities immediately?

I am creating a large number of entities with NHibernate, attaching them to my ISession, and then using a transaction to commit my changes to the database. Code sample is below:
ISession _context = SessionProvider.OpenSession();
//Create new entities
for(int i=0; i<100; i++)
{
MyEntity entity = new MyEntity(i);
//Attach new entity to the context
_context.Save(entity);
}
//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
//Flush the session
tx.Commit();
}
I was under the impression that the line _context.Save() simply makes the ISession aware of the new entity, but that no changes are persisted to the database until I Flush the session via the line tx.Commit().
What I've observed though, is that the database gets a new entity every time I call _context.Save(). I end up with too many individual calls to the database as a result.
Does anyone know why ISession.Save() is automatically persisting changes? Have I misunderstood something about how NHibernate behaves? Thanks.
***EDIT - Just to clarify (in light of the two suggested answers) - my problem here is that the database IS getting updated as soon as I call _context.Save(). I don't expect this to happen. I expect nothing to be inserted into the database until I call tx.Commit(). Neither of the two suggested answers so far helps with this unfortunately.
Some good information on identity generators can be found here
Try:
using(Session _context = SessionProvider.OpenSession())
using(var tx = _context.BeginTransaction())
{
//Create new entities
for(int i=0; i<100; i++)
{
MyEntity entity = new MyEntity(i);
//Attach new entity to the context
_context.Save(entity);
}
//Flush the session
tx.Commit();
}
Which identity generator are you using? If you are using post-insert generators like MSSQL/MySQL's Identity or Oracle's sequence to generate the value of your Id fields, that is your problem.
From NHibernate POID Generators Revealed:
Post insert generators, as the name
suggest, assigns the id’s after the
entity is stored in the database. A
select statement is executed against
database. They have many drawbacks,
and in my opinion they must be used
only on brownfield projects. Those
generators are what WE DO NOT SUGGEST
as NH Team.
Some of the drawbacks are the
following
Unit Of Work is broken with the use of
those strategies. It doesn’t matter if
you’re using FlushMode.Commit, each
Save results in an insert statement
against DB. As a best practice, we
should defer insertions to the commit,
but using a post insert generator
makes it commit on save (which is what
UoW doesn’t do).
Those strategies
nullify batcher, you can’t take the
advantage of sending multiple queries
at once(as it must go to database at
the time of Save)
You can set your batch size in your configuration:
<add key="hibernate.batch_size" value="10" />
Or you can set it in code. And make sure you do your saves within a transaction scope.
Try setting the FlushMode to Commit:
ISession _context = SessionProvider.OpenSession();
context.FlushMode = FlushMode.Commit;
peer's suggestion to set the batch size is good also.
My understanding is that when using database identity columns, NHibernate will defer inserts until the session is flushed unless it needs to perform the insert in order to retrieve a foreign key or ensure that a query returns the expected results.
Well
rebelliard's answer is a possibility depending on your mapping
you are not using explicit transactions (StuffHappens' answer)
default flush mode is auto and that complicates things (Jamie Ide's answer)
if by any change you make any queries using the nhibernate api the default behaviour is to flush the cache to the database first so that the results of those queries will match the session entity representation.
What about :
ISession _context = SessionProvider.OpenSession();
//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
//Create new entities
for(int i=0; i<100; i++)
{
MyEntity entity = new MyEntity(i);
//Attach new entity to the context
_context.Save(entity);
}
//Flush the session
tx.Commit();
}

S#arp Architecture 1.9 + Fluently.Configure() NHiberbante

I have a need to fluently configure nhibernate in my S#arp application so that I can use a custom NHibernate.Search directory for each of my tenants in a multi-tenant app.
However I have googled for hours looking for a solution but can't seem to find anything current that works.
Thanks,
Paul
I haven't tried this myself, but AddConfiguration takes a dictionary of cfgProperties, which I guess you can pass the tenant specific hibernate.search.default.indexBase value to.
I had a look at this, adding the key as described above will cause a problem if you attempt to use CfgHelper.LoadConfiguration() since it will return null.
But you can configure NHSearch to use different directories for each factory using the factory key:
<nhs-configuration xmlns="urn:nhs-configuration-1.0">
<search-factory sessionFactoryName="YOUR_TENANT1_FACTORY_KEY">
<property name="hibernate.search.default.indexBase">~\IndexTenant1</property>
</search-factory>
<search-factory sessionFactoryName="YOUR_TENANT2_FACTORY_KEY">
<property name="hibernate.search.default.indexBase">~\Tenant2</property>
</search-factory>
</nhs-configuration>
If you are following instructions on
http://wiki.sharparchitecture.net/Default.aspx?Page=NHibSearch
You would need to change the method GetIndexDirectory to
private string GetIndexDirectory() {
INHSConfigCollection nhsConfigCollection = CfgHelper.LoadConfiguration();
string factoryKey = SessionFactoryAttribute.GetKeyFrom(this); // Change this with however you get the factory key for your tenants,
string property = nhsConfigCollection.GetConfiguration(factoryKey).Properties["hibernate.search.default.indexBase"];
var fi = new FileInfo(property);
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fi.Name);
}

Saving an NHibernate object after AutoMapping it to a DTO

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.

NHibernate update on single property updates all properties in sql

I am performing a standard update in NHibernate to a single property. However on commit of the transaction the sql update seems to set all fields I have mapped on the table even though they have not changed. Surely this can't be normal behaviour in Nhibernate? Am I doing something wrong? Thanks
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var singleMeeting = session.Load<Meeting>(10193);
singleMeeting.Subject = "This is a test 2";
transaction.Commit();
}
}
This is the normal behavior. You can try adding dynamic-update="true" to your class definition to override this behavior.
Well. yes this is normal behaviour for NHibernate. You can use generated attribute for your properties to change the behaviour. Details on Ayende's blog.
Why is this default is because with dynamics you don't get your query plan cached. And usually you don't mind that you send few more bytes over high speed network connection between your application server and database. Unless you are saving long strings where this setting is perfectly appropriate.