I'm somewhat new to NHibernate, so this question may be a no-brainer. Anyway, I'm replacing a project at work that uses ADO.NET that will now be using NHibernate(With LinqToNhibernate). This has worked fine so far, but I've run up against a function that needs to search through a large amount of data(about 200,000 records, test each record using a very specific algorithm(something too complicated for LINQ), and if it matches the criteria I want to add it to the results list. In ADO.NET I used a data reader so I wouldn't have to load all the results in memory. Is there an equivalent way to do this in NHibernate? Would the lazy loading be used for this? Thanks!
-
What is the complicated algorithm? – Paco Oct 07 '09 at 21:05
-
Well, I can't post the code since it's for a business. Essentially it looks through VIN(Vehicle Identification Numbers), tests whether it matches a table that ties the number to a specific model of vehicles based on specific locations in the string(VIN). I can't really explain it without you understanding how VIN's work for the state I live in. – Austin Oct 07 '09 at 21:08
-
Is it .Net code or SQL or a mix of both? – Paco Oct 07 '09 at 21:38
-
Do you need to do this a lot of is it a reporting operation? – Paco Oct 07 '09 at 21:39
-
Paco, There is some SQL that just initially narrows down the results a bit(for example, looking at a certain part of the code and realizing I need to pull out all Ferrari's, Fords, etc..) The bulk of it is just .NET code that picks apart strings and tries to apply a match to it according to each record in the results(for example, does this character match, is the next character a wildcard--ok, skip it, etc). – Austin Oct 08 '09 at 01:10
-
In that case I would use the old approach you was using. NHibernate cannot improve this. – Paco Oct 08 '09 at 21:07
3 Answers
Ok from what I remember with the ISession.CreateQuery you can return a list or an enumerable. The List will load all of them into memory (I believe). The IEnumerable will issue a statement to the server to retrieve all of the Ids from the server. Every time you iterate through the ienumerable, it'll check the cache and if it's not in the cache, it'll issue a database call to retrieve the information.
Neither of them is what you want. You either use a ton of memory or hammer the DB.
I really sounds like you're trying to do some kind of ETL operation. Your best bet is to keep a couple of specialized pieces of code around to handle this situation.
If you insist on using NHibernate I would just page through the results in manageable chunks and use stateless sessions here:
http://davybrion.com/blog/2008/10/bulk-data-operations-with-nhibernates-stateless-sessions/

- 2,975
- 1
- 19
- 24
-
Hey, sorry--I forgot to mention I'm using LinqToNhibernate so I don't use queries(other than Linq). – Austin Oct 07 '09 at 21:23
-
I don't see what the problem is of using HQL or ICriteria as well if you abstract all your data-access away in a repository. AFAIK, LinqToNhibernate isn't very mature yet ... – Frederik Gheysels Oct 07 '09 at 21:26
-
Frederik, I'm not using the repository pattern because I haven't yet found a need for it. It's easiest right now just to manage the session and queries in the Business layer. And yea, I've found some limits in LinqToNhibernate that need to be worked out(no joins), but so far it's worked very well. – Austin Oct 08 '09 at 01:12
-
In linq you can still do a Take - Skip operations in order to do paging in order to handle your memory. – Min Oct 08 '09 at 02:58
-
Thanks! I think the Take operation will probably work--I remember now reading about that extension. – Austin Oct 09 '09 at 17:11
As you might know, when using NHibernate you have to approach working with data in a completely different manner. You're no longer with 'raw data' that comes from the DB like you do in ADO.NET; rather you're working with an OO view on your data.
You do not query the database / tables in NHibernate, but instead, you're querying your entities.
I think that the solution for your problem, can be found in projections.
With a projection, you can create your query in NHibernate (using HQL or the ICriteria API).
But, before you execute the query, you specify, via a projection, which properties you're interested in.
NHibernate will then execute a query which retrieves only those properties. This also means that it is not really the entities that are returned. It is rather a DTO that is returned.
So, you will have to create a class which will act as this 'DTO'. It only has the properties that you're interested in, and you also have to 'import' this class so that it is known to NHibernate.
A while ago, I explained on SO how you could use projections. It can be found here

- 1
- 1

- 56,135
- 11
- 101
- 154
For an edge case backward compatibility like the one you have, you can just create a DbCommand
and ExecuteReader
on it, like this
using (var session = this.SessionFactory.OpenSession())
{
using (DbCommand command = session.Connection.CreateCommand())
{
command.Connection = session.Connection;
command.CommandText = queryString;
Command.CommandTimeout = 60 * 100;
Command.CommandType = CommandType.Text;
var parameter = Command.CreateParameter();
parameter.ParameterName = "@ParamName";
parameter.Value = whatever_value;
Command.Parameters.Add(parameter);
var dataReader = Command.ExecuteReader(CommandBehavior.CloseConnection);
// TODO: Enumerate your data reader
}
}

- 4,049
- 1
- 29
- 46