Ayende @ Rahien

Refunds available at head office

NHibernate Query Analyzer And DuplicateMappingException

One of the most common issues that people have run into with using NHQA is the DuplicateMappingException. The root problem is that you are adding both the DLL (which contained embedded resources mapping files) and the mapping files themselves.

Well, after getting tried of answering that question so often, I decided to fix the issue, and let NHQA knows about the issue, and try to resolve it. The fix is in the repository now, but I would like to have some more input before I would release it.

NHibernate Query Generator - Collection querying

In the repository (Exists / NotExists):

   1:  [Test]
   2:  public void CanQueryOverCollections()
   3:  {
   4:      User one = User.FindOne(Where.User.Blogs.Exists(
   5:                                  Where.Blog.Name == "Ayende @ Blog"
   6:                                  ));
   7:      Assert.IsNotNull(one);
   8:  }
 
Will result in:
 
   1:  SELECT this_.Id as Id4_0_, this_.Name as Name4_0_, this_.Email as Email4_0_ 
   2:  FROM Users this_ WHERE exists (SELECT this_0_.Id as y0_ FROM Blogs 
   3:  this_0_ WHERE this_0_.Name = @p0)

 

Fluent interfaces? Take that.

NHibernate Query Analyzer for NHibernate 1.2 GA

I am a bit late with this one, but here is a new version for NHibernate 1.2 GA. This also supports Castle Active Record, hopefully in a version neutral way.

You can get it here, or admire the UI here:

image

As an aside, I am thinking about adding Criteria Query functionality, since this is something that I use a lot. I am not sure yet what form this would take, at any rate it would involve runtime code generation, so that is complex (and sort of fun/pain).

I am opened to ideas.

Have fun...

NQA 1.2.3: Opps, My Bad

I package it without including the app.config, which means that the application fails when you start it up.

Please try downloading it again.

Fix for "Cannot find custom tool 'NHibernateQueryGenerator' on this system."

If you have downloaded NQHG 1.7 and are trying to use it from Visual studio, you probably got the following error:

Cannot find custom tool 'NHibernateQueryGenerator' on this system. The issue is that I didn't update the setup script correctly, and the version that it registers as a COM addin is set to 1.6, while the assembly version is 1.7. This cause the COM load to fail.

This script will reset the NHQG version to the correct one, until I manages to find some time for fixing this properly.

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{DE8A7135-96F6-47BA-9DC9-D7D837B4CDE3}]
@="NHibernate.Query.Generator.NHibernateQueryGenerator"

[HKEY_CLASSES_ROOT\CLSID\{DE8A7135-96F6-47BA-9DC9-D7D837B4CDE3}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{DE8A7135-96F6-47BA-9DC9-D7D837B4CDE3}\Implemented Categories\{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]

[HKEY_CLASSES_ROOT\CLSID\{DE8A7135-96F6-47BA-9DC9-D7D837B4CDE3}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="NHibernate.Query.Generator.NHibernateQueryGenerator"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="C:\\Program Files\\Rhino\\NHibernate Query Generator\\NHQG.exe"
"Assembly"="NHQG, Version=1.7.0.0, Culture=neutral, PublicKeyToken=0b3305902db7183f"

[HKEY_CLASSES_ROOT\CLSID\{DE8A7135-96F6-47BA-9DC9-D7D837B4CDE3}\InprocServer32\1.7.0.0]
"Class"="NHibernate.Query.Generator.NHibernateQueryGenerator"
"CodeBase"="C:\\Program Files\\Rhino\\NHibernate Query Generator\\NHQG.exe"
"RuntimeVersion"="v2.0.50727"
"Assembly"="NHQG, Version=1.7.0.0, Culture=neutral, PublicKeyToken=0b3305902db7183f"

[HKEY_CLASSES_ROOT\CLSID\{DE8A7135-96F6-47BA-9DC9-D7D837B4CDE3}\ProgId]
@="NHibernate.Query.Generator.NHibernateQueryGenerator"

NHibernate Query Analayzer 1.2 Beta: Now With Active Record Support

There is a new build of NQA out, this time it works against (and only against, sorry) NHibernate 1.2 Beta 2.

This time I also added support for Active Record. All you need to do is add the Active Record assembly to your project, add the app.config, and you are set. The only requirement is that the Active Record configuration section will be named "activerecord".

Now you should be able to execute queries against your objects directly. This release is marked as beta, since I have not yet been able to give it the testing that it needs. Let me know how it goes.

You can get the bits here.

NHibernate 1.2 Beta 2 - Performance

I was asked to help an application that was suffering un-optimal performance with NHibernate today. The first thing that I did was upgrade the application to NHibernate 1.2 (which took some time, damn non-virtual methods).

After I was done, I run the application, and was basically done. Just by upgrading to 1.2, we saw a major performance improvement. Now, to be fair, this is not just because NHibernate 1.2 is so much better (although it is :-) ). It is that it has different defaults (specifically about lazy loading) that make a huge difference in performance.

NHibernate Query Generator 1.7

Well, it is certainly an interesting release. This release contains very little code of mine, mainly minor adaptations of two wonderful patches that were sent to me.

  • The first by Bas Jansen - which added inheritance detection from the mapping files.
  • The second by Adam Tybor - which added support for projections and group by.

Me, I just fixed a stupid bug by yours truly that would refuse to recognize exe as valid assemies, and put those two patches together.

Together, they make quite an addition to NQG. Especially when combined with some thing that can really understand projections... which is soon to come.

You can get it here.

NHibernate Generics: Deprecated On 1.2

I have updated NHibernate Generics to support NHibernate 1.2 . This update is very minimal and was done to ensure that you can move code to the NHibernate 1.2 without breaking stuff.

Please consider NHibernate Generics library use as deprecated with NHibernate 1.2 and above.

NHibernate Generics (NG from now on) always had two purposes. The first was to give generics capabilities to NHibernate, so I wouldn't have to do casts all over the place. The second was to automatically handle assoications between objects using anonymous delegates and a sprinkle of magic.

I wrote this library nearly a year ago, and I have learned a lot since then, not the least of which, I learned what is the cost of magic. There are design assumption built into the library that are now proven to be false, specifically, when you want/don't want to force lazy load and working with the second level cache.

When I find myself scratching my head and trying to understand what is happening in the code I know that it is doing too much behind my back.

We no longer need external Generics support, since it is now (1.2) built into NHibernate.  And I had a lot of fun and a number of serious issues with the automatica assoication handling, so I don't see much of a point in continuing that.

You can find the code here, just check out and compile, I am currently not planning to create a binary release.

Extending NHibernate Query Generator Code

So it has been out for 24 hours, and I got a couple of bug reports (fixed) and some interesting feedback. Ken is asking how you can extend the generated code and use SQL Functions from it. I had to fix a couple of issues which had to do with the amount of code I generated, right now I reduced the amount of code generated by 40% (with no affect of functionality, of course).

After those changes (which also include making everything partial, we can start extending the Where class, this turned out to be a fairly easy, check this out:

namespace Query

{

      public partial class Where

      {

            public partial class Root_Query_User

            {

                  public virtual QueryBuilder<User> IsInGroup(string groupName)

                  {

                        QueryBuilder<User> queryBuilder = new QueryBuilder<User>("this", null);

                        AbstractCriterion sql = Expression.Sql(
                                new SqlString("? in (select 'Administrators')"),
                                                       groupName, NHibernateUtil.String);

                        queryBuilder.AddCriterion(sql);

                        return queryBuilder;

                  }

            }

      }

}

 

This is a silly little expression, but it shows that you still have the power to extend the code to allows whatever you want, and still get very good OO syntax. We can now use this like this:

User.FindOne(Where.User.IsInGroup("Administrators"));

One thing to note, I explicitly extend Root_Query_User, this is because if I want to extend Query_User<T1>, I would need to make the criterion join-safe (in this case it is, but it is better to be safe) which can be quite hard.

Update: After applying Ken's suggestion (in the comments), it shrank to:

public partial class Where

{

      public partial class Root_Query_User

      {

            public virtual QueryBuilder<User> IsInGroup(string groupName)

            {

                  AbstractCriterion criterion = Expression.Sql("? in (select 'Administrators')",

                                                               groupName, NHibernateUtil.String);

                  return FromCriterion(criterion, "this", null);

            }

      }

}

Much cleaner, thanks Ken.

The New Repository: Rhino Tools

Following the advice from the comments, I have managed to consolidate my various OSS SVN repositories into a single one, hosted at source forge.

I was quite suprised that it was so much, to tell you the truth.

The repository URL is:

https://svn.sourceforge.net/svnroot/rhino-tools/trunk/

To checkout, execute:

There is no password necceary for reads. I'll be update the various links on the site to point to the correct location soon.

NHibernate Query Generator 1.2

NQG will now automatically create the NamedExpression and ManyToOneNamedExpression files, in a language of your choice, so you basically point it at a directory, let it run, and then just include all the files in that directory.

You can get it here.

Update: I fixed the warning in the generated files, and gave it a name without spaces, so it wouldn't break on download.

Using NHibernate.Generics with NHibernate 1.2

If you are using NHibernate.Generics with NHibernate 1.2, you may run into casting issues, this is because NHibernate.Generics and NHibernate 1.2 both tries to make the collections generic.

You can either stop using NHibernate.Generics (their main purpose, allowing generic collections in NHibernate) is no longer needed. But their secondary purpose, automatic syncronization between related properties is very nice in many scenarios. Until I'll get around to porting them to 1.2, you need to specify generic="false" in the mapping of all collections that uses NHibernate.Generics for them to work.

NHibernate Query Generator Updates

I just added support for <componet> and <dynamic-component> (in the SVN only, for now).

I'm considerring adding support for projections and the new expressions in NHibernate 1.2, any suggestions? I though about something like:

Projections.Blog.Posts.Count

And:

Projections.Blog.Date.Max

Suggestions?

NHibernate Generics 1.0.12

I got a couple of complaints about regression in NHibernate Generics 1.0.11, about using an abstract class. I hope that this would fix the issue.

Code and binaries are here

New Version of NHibernate Query Generator

After using it for a couple of days, I made the following improvements:

  • Added Eq() and IdIs() to many-to-one references, so now I can issue this statement:
    ICollection<Order> orders = Repository<Order>.FindAll( Where.Order.Customer.IdIs(15) );
    It seems like we are using this quite a bit in our applications, mainly from query strings.
  • Added support for VB.Net
  • Create a VS.Net Custom Tool, so now you wouldn't have to mess with the command line, just specify "NHibernateQueryGenerator" as the custom tool, and you are done.
  • Create an MSI installer for it, so it is really close to zero friction now.

You can get it here.

Introducing the NHibernate Query Generator

Okay, it looks like I can track down fairly easily what books I read, when I read Working Effectively with Legacy Code, I wrote Rhino Mocks. Now I am reading Applying Domain-Driven Design and Patterns, and I wrote the NHibernate Query Generator.

So, what is this all about?

NHibernate has two major API for querying objects. The first one is called the query API, and uses HQL, a language similar to SQL but with OOP aspirations. The second is called the criteria API, and it is far simpler API, but it is also much easier to use.

Here is a simple example of using the criteria API using my Repository sample from yesterday:

ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(Expression.Eq("City""London"));

Now, those of you that already knows me know that I have a passionate dislike to strings. I wrote a mock objects library because of this issue, so I may need physcological therapy in the future, but I hate strings.

Well, what do I do when there is something that I don't like? I fix it.

In this case, there where two main options, run time proxying and code generation.

Run time proxying is similar to what I do in Rhino Mocks, and it may look like this:

ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(Expression.Eq(Expr.Of<Customer>().Name,"London"));

This has the disadvantages of being both ugly and complex, so I turned to the other route. I build a small application which takes an NHibernate mapping file (hbm.xml) file, and output a strongly typed query wrapper. The above query can now be used like this:

ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(
   Where.Customer.City.Eq("London") );

This is much better, and of course that you get all the other nice things about the expression API (like Between, In, etc).

You can get it here, binaries only. Source would have to wait for a while, my subversion provider has run out of room. Note that the code it generates relies on a class called NamedExpression. The class is included in the binary, so just add it to your project and you are done.

I also added support for queries, since I didn't want to leave the other side of the API high and dry, it means that you can do this:

ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(
    Queries.AllCustomersInCity, new Parameter("city""London"));

Here is a little FAQ

  • What does it generate:
    The tool generate strongly typed wrappers for each of the mapped entities and each of their properties. At the moment, is supports querying against properties, many-to-one, and ids.
  • How to make it work for all the files in a directory?
    Simply use the batch capabilities of the shell, like this:
    for %f in (*.hbm.xml) DO "NHibernate.Query.Generator.exe" %f D:\Queries
    This will run the tool over all the files in the directory, and output them all to the Queries dir.
  • How to make it work with ActiveRecord?
    You need to use the isDebug="true" flag in the configuration, and then point the tool to the resulting mapping files.
  • Can I get is as a custom tool for Visual Studio?
    It shouldn't be hard to do, but I don't have the time at the moment. Feel free to send me a patch for it when I release the code.

NHibernate.Generics 1.0.7

I'm pretty ashamed to admit it, but I managed to foul up IEnumerator<T> for EntityDictionary<T,K>. I was very surprised to realize this, I assure you, I thought that at this point I could be trusted to handle a simple collection delegation, but apperantely this is not the case.

There is a new version which fix this issue, add some better error messages, etc. As usual, you can get it here.