Rhino Query: Implementation Considerations

time to read 8 min | 1569 words

It probably surprises no one that I'm interested in creating a strongly typed query support for NHibernate. Cecil is going to do most of the hard work, which means that I'm left with the more interesting project of turning an AST into a query. Part of the problem is that the whole thing is exactly opposite to the way you think about it.

Consider this query:

string name = "Ayende"
delegate(Blog b) { return b.BlogName == name; });

This gets messy fast because both the C# compiler and Cecil has a go at obsfucating it. The object graph that I get looks something like this:

  • Assign
    • To: local_var_0
    • From: method_call:
      • Name: string::op_Equaility
      • Arguments:
        • Method call:
          • Blog::get_Name
        • Field reference:
          • some random name that the compiler generate for the anonymous method
  • Branch to:
    • Next instruction - no idea why this is there
  • Return:
    • local variable reference:
      • local_var_0

From this, I need to construct something that will resemble this:

session.CreateCriteria(typeof(Blog)).Add(Expression.Eq("Name""Ayende")).List(); 

I've some ideas as to how to get this, but none of them is very obvious, and all of them rely on the user not doing something very complex. Basically, the idea is to iterate over the method and create a reverse tree, from each return statement, we go backward to find out what is going on there. So, in this case, we will do something like:

  • Return local_var_0
    • Find last assignment to local_var_0
      • Get expression that did the assigment
        • ? This is the hard part, I'm guess here.
        • Determain which op_ was executed here or throw if this is not an operator action.
        • Determain whatever there is chaining via either && or ||, and add them as well.

Basically, two very hard parts (parsing the IL and generating the query) are done, they are working and can be used as is. The hard part is to match the two together.