views:

3961

answers:

5

I'm using a custom named query with NHibernate which I want to return a collection of Person objects. The Person object is not mapped with an NHibernate mapping which means I'm getting the following exception:

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.

It's getting thrown when the Session gets created because it can't find the class name when it calls NHibernate.Cfg.Mappings.GetClass(String className). This is all fairly understandable but I was wondering if there was any way to tell NHibernate to use the class even though I haven't got a mapping for it?

A: 

By using the class, NHibernate would basically be guessing about everything involved including which table you meant to use for Person, and the field mappings. NHibernate could probably be hacked to do dynamic binding based on matching the names or something, but the whole idea is to create the mappings from plain old data object to the database fields using the xml files.

dnewcome
A: 

If there's not a really good reason not to map the class, simply adding the mapping will give you the best results...

That said, you can't use a named query to directly inject results into an unmapped class. You would need to tell it which columns to put into which fields or in other words, a mapping. ;) However, you can return scalar values from a named query and you could take those object arrays and build your collection manually.

Stuart Childs
+1  A: 

To solve this, I ended up using the TupleToPropertyResultTransformer and providing the list of property values. There are a few limitations to this, the main one being that the SQL query must return the results in the same order as you provide your properties to the TupleToPropertyResultTransformer constructor.

Also the property types are inferred so you need to be careful with decimal columns returning only integer values etc. Apart from that using the TupleToPropertyResultTransformer provided a reasonably easy way to use an SQL query to return a collection of objects without explicitly mapping the objects within NHibernate.

lomaxx
+6  A: 

Why don't you use:

query.SetResultTransformer(Transformers.AliasToBean(typeof(Person)));

It will insert data from each column in your query into Person object properties using column alias as a property name.

Michał Piaskowski
+1  A: 

How can you create a query which would return instances of a type that is not mapped ?

I think Michal has a point here, and maybe you should have a look at projections. (At least, this is what I think you're looking for).

You create a query on some mapped type, and then, you can 'project' that query to a 'DTO'. In order to do this, you'll have to 'import' your Person class, so that it is known to NHibernate, and you'll have to use a ResultTransformer.

Something like this:

ICriteria crit = session.CreateCriteria (typeof(Person));

// set some filter criteria

crit.SetProjection (Projections.ProjectionList()
                     .Add (Property("Name"), "Name")
                     .Add (Property( ... )
                   );

crit.SetResultTransformer(Transformers.AliasToBean(typeof(PersonView));

return crit.List<PersonView>();

But, this still means you'll have to import the class, so that NHibernate knows about it.

Frederik Gheysels
projections aren't quite what I'm looking for, but the TupleToPropertyResultTransformer or the AliasToBean transformer does the job. I don't have access to the class to give it a new constructor to use the AliasToBean transformer tho so I'm using the TupleToPropertyResultTransformer
lomaxx