configure Fluent NHibernate mapping to allow INSERT only? - nhibernate

I'm moving a project from SubSonic to NHibernate and am using Fluent NHibernate to perform all of our mapping. Our db schema is pretty straight forward and most of our cases appear thus far to be well illustrated by different blog posts and sample code that's available.
One thing that I'm unable to figure out however is the ability to Map a column so that its value is only allowed to be set on the initial INSERT of the data. It's a generated value on our app tier, and once inserted, we don't want to allow it to be updated any further.
I tried the obvious (but wrong)
Map(x => Foo).ReadOnly()
What would be the appropriate function chain to accomplish what I'm after?

After much experimentation--
Map(u => Foo).Not.Update();
Appears to be doing what I desire--but I'd love if more experienced hands chimed in to confirm that my interpretation of the results is accurate. i'd hate to mark this as the answer and inadvertently send future visitors down the wrong path.

Related

Getting/building the SQL (with parameters) from NHibernate 3.2

I am working on a project that requires the following:
Extract the full SQL query from a specific NHibernate 3.2 session.
Perform specific actions on the query (i.e not necesserily log it)
Do not affect NHibernate in the whole system to avoid introducing performance issues
I checked several approaches, many of them already appearing on StackOverflow. Here are my options as I see now:
Manual
In the most naive and annoying solution, I can just follow the business logic and build the query myself - E.g, if the BL builds a criteria that does a restrictions on ID=5, I'd build a query with SELECT ... WHERE ID = 5. Since we have quite a complex BL, I'd really like to avoid that.
NHibernate interception
Originally, using the OnPrepareStatement seemed like the best bet. However, I soon discovered that the parameters of the query aren't logged which renders it quite useless.
Introspecting NHibernarnate’s ICriteria
When performing a query with NHibernate, we do it with an ICreteria object that contains the restrictions, the sorting and the aggregations definitions. It seems I could interspect it when a CriteriaWalker that is described here. However, it seems that it gets confused on complex queries. Also, in some cases we use NHibernate 3 new "QueryOver" syntax for which this solution doesn't help me.
Using ILoggerFactory
Since NHibernate 3, you can write custom log factories (sample). This gets the full SQL, however, it also affects the whole NHibernate system and it seems it is impossible to have a factory to apply for a specific ISession, or even ISessionFactory.
Custom NHibernate driver
I've considered writing a proxy NHibernate driver and assigning it to a specific SessionFactory (as described here). However, a friendly comment warns that it longer works in Nhibernate 3.2.
Using dynamic proxies
This code uses Castle's Dynamic proxies to inject itself inside ISession. I haven't tried running it yet with my server, but I am a bit wary of using such drastic measures. If nothing else works, however, I guess it is something to consider.
Suggestions?
Right now I am a bit stuck on choosing the best way to go with since nothing seems to be doing its job, quite right. If there are other suggestions, I'd love to hear them.
I'd use a standard or custom logging framework, and apply a custom filter to retrieve a flag from thread data (for example) in order to determine whether the session should be logged.
This way, you don't mess with NH internals at all, and as long as you don't set the flag, nothing gets logged.

What is the .Fetch.Select() in Fluent nHibernate?

While developing with Fluent nHibernate, I notice that on relationships I can specify a Fetch property, with possible options of Select(), Join(), and Subselect().
I did some searches for these and yielded very little information. I did find them in the nHibernate documentation and the fluent nHibernate documentation, but it does little other than give their signatures, which doesn't help me too much.
I was wondering if there is any real explanation for what these are, and what they really do. I've been rather perplexed myself. From my own evaluation they seem to change the way that referenced entities are pulled into the object graph, but I've yet to entirely discern how they change it, and which one is optimal for what situation...
I did find this blog post (http://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/) that has a little bit of detail but I'm still pretty perplexed about the entire situation. I've also seen other examples that state using Select() is more optimal, but the reasoning behind it. Additionally I found a post at (http://community.jboss.org/wiki/AShortPrimerOnFetchingStrategies) that is geared towards the original Java Hibernate platform, but I presume the concept is the same. In this one, my theory seems to be blown a bit as it focuses more on the lazy loading aspect of what they do, but I've still not seen any really flat examples.
Join fetching - NHibernate retrieves the associated instance or collection in the same SELECT, using an OUTER JOIN.
Select fetching - a second SELECT is used to retrieve the associated entity or collection. Unless you explicitly disable lazy fetching by specifying lazy="false", this second select will only be executed when you actually access the association.
Subselect fetching - a second SELECT is used to retrieve the associated collections for all entities retrieved in a previous query or fetch. Unless you explicitly disable lazy fetching by specifying lazy="false", this second select will only be executed when you actually access the association.
Check out the fetching strategy document # The Nhibernate Documentation
I'm not really familiar with nHibernate (I work with Hibernate and Java), but based on analogy, this enables you to specify association/collection property which you want to load eagerly, with the given entity. This is useful when you don't have full control over (n)Hibernate sessions (i.e if some other framework like Spring in Java is taking care of sessions/transactions).
So your assumption is basically correct.
Select, Join, and Subselect are the ways to obtain the related property, and determine what kind of query will be performed in database. Which one is optimal, really depends on the situation you have.
Hope this helps a little,
Cheers.

How do I strongly type criteria when using NHibernate's CreateCriteria method?

I'm currently using NHibernate, for the first time, with Fluent NHibernate. I've gotten everything setup nicely, however now I've come to actual doing some data retrieval, it seems to have fallen short.
I was expecting NHibernate, to allow me to do something like:
session.CreateCriteria<TblDocket>()
.Add(Restrictions.Eq(x=> x.DocketNumber, "10101"));
However, this doesn't appear to be the case and I seem to have to write:
session.CreateCriteria<TblDocket>()
.Add(Restrictions.Eq("DocketNumber", "10101"));
That'll be less-than-wonderful when I rename any properties! I've always though hard coded strings in code is bad, especially when the strings relate to property names.
Is there any way I can strongly type these restrictions? I had a look at this blog post, but it seems quite messy, is there a nicer solution?
I decided to use NHibernate.Linq instead. I found a brilliant tutorial here.
You can't using out-of-the-box NHibernate.
There is a project called NHibernate Lambda Extensions which allows you to do this with some limitations.
since NHibernate 3.0 there is also QueryOver available which are a nice typesafe wrapper around the criteria API.
session.QueryOver<TblDocket>()
.Where(x => x.DocketNumber, "10101");
For anyone who comes along this post and doesn't like linq or isn't too familiar with lambda you can still safely use ICrierta's such as
session.CreateCriteria<TblDocket>().Add(Restrictions.Eq("DocketNumber", "10101"));
what you need is helper classes so you can remove the magic strings such as "DocketNumber" so that if you do change your property names or column names these are taken care of for you or will atleast produce a build error so you know before you publish your code.
Anyone wanting to see an example can have a look at NhGen ( http://sourceforge.net/projects/nhgen/ ) and the query examples at https://sourceforge.net/projects/nhgen/forums/forum/1169117/topic/3789112 which show how helpers classes can be used like.
// Find using a simple entity query
IList<IMessage> messageList3 = messageDao.Find( new [] { Restrictions.Le(MessageHelper.Columns.Date, dateLastChecked) } );
Note that this project also created entity wrapper classes which group all your common CRUD methods into one class (xxxDao as show above) so you don't have to keep copying the same code over and over again.

Getting Started with Fluent NHibernate

I'm trying to get into using Fluent NHibernate, and I have a couple questions. I'm finding the documentation to be lacking.
I understand that Fluent NHibernate / NHibernate allows you to auto-generate a database schema. Do people usually only do this for Test/Dev databases? Or is that OK to do for a production database? If it's ok for production, how do you make sure that you're not blowing away production data every time you run your app?
Once the database schema is already created, and you have production data, when new tables/columns/etc. need to be added to the Test and/or Production database, do people allow NHibernate to do this, or should this be done manually?
Is there any REALLY GOOD documentation on Fluent NHibernate? (Please don't point me to the wiki because in following along with the "Your first project" code building it myself, I was getting run-time errors because they forget to tell you to add a reference. Not cool.)
Thanks,
Andy
I've been using Fluent NHibernate Automapping for a few months now. I'm by no means an expert, but can take a stab at your questions...
FNH Automapping does indeed create DB schemas from POCO classes, including lists of other objects (this was the reason I chose NHibernate in the first place).
When you change schemas, you have to rerun the automapping, which does drop the whole database, unfortunately. In my case, it's not a big problem because I'm importing existing binary data files, so I just have to re-import my data every time the schema changes. I've read that there's some data migration support available with NHibernate, but have no experience with this. (BTW, Subsonic will do data migration, but it's automapping functionality is far more rudimentary - at least it was when I evaluated it a few months ago)
FNH documentation is one of my pet peeves - they have not even added Intellisense help on the method names, etc. (But they get really huffy when you point that out - ask me how I know!) I've made a couple of edits to the wiki when I could, but there's so much more that could be done there. The best approach is to start with a working example (i.e.
this one from Nikola Malovic, and post questions to the support form if (when!) you run into trouble. In general, I've found the FNH community pretty helpful, and have been able to work through all my difficulties. They've also fixed a couple of bugs I've found.
Overall, using FNH has been a huge win for my project - highly recommended!
I don't use Fluent, but I can help with classic NHibernate.
yes, the creation of the schema is very recommendable for production use (Schema Export). When you do this is up to you. For instance, you could create the database by an installer. You shouldn't drop existing databases, but this is a decision of you application.
I don't understand this question. Do you mean you need to upgrade an existing database to a new database schema? This is unfortunately something you need to implement yourself. NH can't do much about this, because it is very specific to you data and the changes you made. There is also a Schema Update or something like this, which is not recommended for production use.
I don't use Fluent, so I can't help here.

Fluent NHibernate. Auto Mapping and Conventions

Im new to NHibernate, the configuration aspect of it has always seemed overly onerous to me. Yesterday, I came across the Auto Mapping features of Fluent NHibernate and was suitably impressed.
To educate myself, I set myself the challenge of attempting the 'Getting Started First Project' (http://wiki.fluentnhibernate.org/show/GettingStartedFirstProject) using AutoMappings and Conventions. I have to admit to not having much luck.
To summise my steps:
I made some minor changes to the database schema in the example, mainly to remove the underscores from the foreign keys (i.e. Product_id to ProductId) as this would bring it more inline with our database naming standards.
Q1) I tried to write a IHasManyConvention implementation using the ForeignKeyConvention as an example but the WithKeyColumn method doesnt seem to exist (I presume this is because I downloaded yesterdays build so subsequently the design has changed since the article was written). How do I rectify this?
I also made some minor changes to the Entities layer in the example as I thought this would make it easier, they were to rename StoresStockedIn to Stores (Product.cs) and Staff to Employees (Store.cs).
My code looks like this:
var cfg = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ConnectionString(c => c
.Is(connectionString)))
.Mappings(m => m.AutoMappings.Add(
AutoPersistenceModel.MapEntitiesFromAssemblyOf<Store>()
.Where(t => t
.Namespace == "FluentNHibernateTesting.Entities")
.ConventionDiscovery.Setup(c => c.Add<ForeignKeyConvention>())
))
.BuildSessionFactory();
I then try and add the stores, products and employees to the database as per the getting started example. The exception I get happens on the Commit and is:
object references an unsaved transient instance - save the transient instance before flushing. Type: FluentNHibernateTesting.Entities.Employee, Entity: FluentNHibernateTesting.Entities.Employee
Q2) How do I resolve this problem? I understand (from my limited reading) that it has something to do with setting up the cascade elements of object relationships correctly but Im a bit stumped about how to go about this effectively using Auto Mapping.
Q3) Is there a target release date for the Fluent project? I (like I assume many others) feel this is an excellent initiative but am mindful of using it unless it is in a stable state.
Q4) Its mentioned in many of the blogs that they are working steadily towards parity of the features in Fluent with hbn.xml. Is there a list of these missing features somewhere in order to aid with the evaluation and usage of this tool?
Appreciate the help in advance.
I asked James Gregory the same questions in an email to him directly. He provided this excellent response.
'Hey Paul,
1) KeyColumnNames is what you're after.
2) You can do this one of 3 ways. Setup a IHasManyConvention to globally make all relationships cascade, use a ForTypesThatDeriveFrom call, or an automapping override.
3) We're in private testing of our 1.0 release now. Unsure whether we'll have a public beta or straight to release, but that should happen in the next few weeks.
4) It's very unlikely we'll ever be completely feature complete with NHibernate, we have no desire to be. Many of the NH features are extremely esoteric, and there is little benefit to us implementing them. As of 1.0 there will be very few features that we don't support that people use regularly. I can confidently say all common mapping scenarios are catered for, and if there's anything that isn't you can always drop back to hbm for that case.
To pre-empt any comments that our docs are out of date, documentation is going to be overhauled for 1.0 ;)
James'
Thanks James.
Is there a target release date for the
Fluent project? I (like I assume many
others) feel this is an excellent
initiative but am mindful of using it
unless it is in a stable state.
You should be able to get a working version of Fluent nHibernate from their SVN repository now. They also have compiled binaries.
There currently aren't any official releases of Fluent NHibernate. This is not a reflection of quality, but of our rapid rate of change. Our code-base is being updated daily , which makes putting out official releases a pointless endeavor until we achieve feature parity with NHibernate Core. Most of the regular features you use day-to-day are ready.
http://fluentnhibernate.org/downloads
The current issues are here:
http://code.google.com/p/fluent-nhibernate/issues/list
None of them appear to be deal-killers. I guess it depends on how much time you have to experiment.
object references an unsaved transient
instance - save the transient instance
before flushing. Type:
FluentNHibernateTesting.Entities.Employee,
Entity:
FluentNHibernateTesting.Entities.Employee
If you Google object references an unsaved transient instance, you will find several matches for this. Your best bet is to start going through these and troubleshooting. Anecdotally, from what I've read it sounds like the error message means exactly what it says, or there is a many-many or cascading relationship that is not getting updated.