Aug 10, 2009 / nhibernate ~ .net ~ rubyonrails
Get a Rails-Stylee Interactive Shell For Your NHibernate Backed Domain Model

If you've ever used Ruby on Rails you'll be aware of the goodness that is script/console. The console lets you interact with your domain model from a terminal - no need for dedicated GUI screens or tools.

If you can't see the benefits, then think about this: Have you ever used SQL Server Management Studio to inspect some data in your tables, or even to tweak a value in a column? Yes? Well, imagine being able to inspect items in your domain model, and even create new objects, invoke behaviours (call methods), update properties etc. It's very handy, and useful for quickly checking or updating data.

I've always missed having this feature during .NET development. The good news is that's it's quite easy to do using IronPython or IronRuby. My EngineRoom partner, Chris Owen, first got this hooked up using IronPython - so credit to him! Since I'm more familiar with Ruby I'll use that in this post.

How To Do It

1. Download Iron Ruby

It's only 4MB, so this will take you about 1 minute. You can get IronRuby from the IronRuby site. I'm got the latest - 0.9.0.0.

2. Extract ZIP to Somwhere Nice

I simply extracted this to a place where I keep my 3rd party libs.

3. Get Your Console On!

Launch the Visual Studio Command Prompt, and navigate to your solutions bin folder. I actually navigated to my ASP.NET MVC apps bin folder, but any folder with your domain logic DLLs will do.

> cd c:\Code\Portal\Web\bin

Now launch IronRuby. You'll get an interactive console.

> c:\CodeLibs\ironruby\bin\ir.exe

IronRuby 0.9.0.0 on .NET 2.0.50727.3053
Copyright (c) Microsoft Corporation. All rights reserved.
>>>

Now we need to do something interesting. Firstly, we need to get some DLLs into scope. Lets load Portal.Core which contains my solutions business objects and data access code.

>>> require 'Portal.Core'
=> true

Note that the Ruby console always spits out the result of the action. In this case, it evaulated to true (success!).

Now I want to start using a few namespaces (as you would a c# file)

>>> import Portal::Core::Infrastructure::DataAccess
=> Object
>>> import Portal::Core::Domain::Entities
=> Object

4. Configure NHibernate

Now for the fun bit! I'm going to first configure my NHibernate Unit of Work class so I can get a NHibernate session (the code for my class is up on GitHub, I use it on many projects). Don't worry about this, you could also create a normal NHibernate configuration and configure the session using hibernate.cfg.xml.

>>> UoW.Configure('data source=.\\SQLEXPRESS2008;database=TestDevelopment;trusted_connection=True', UoW::Environment.Other)
=> nil
>>> UoW.Start
=> nil

I now have a Unit of Work which is started and which gives me access to an NHibernate Session. Great!

Now to do a query.

>>> query = UoW.Session.CreateQuery("from Person p where p.Forename = 'Tobin'")
=> from Person p where p.Forename = 'Tobin'

That's created the query, now I need to execute it. In c# I would write query.List<Person>(). IronRuby has a weird syntax for generic overloads, but they're woring on improving it I hear.

>>> people = query.method(:list).of(Person).call 
=> [Portal.Core.Domain.Entities.Person]

So, I now have a list of People. I could now grab one of them and play around with it.

>>> people.Count
=> 1
>>> tobin = people[0]
=> Portal.Core.Domain.Entities.Person

Lets see what methods the tobin object has.

>>> tobin.methods
=> ['default_group', 'email', 'email=' ... (truncated)

I can now delete myself. This will call some domain logic behind the scenes.

>>> tobin.IsActive
=> true
>>> tobin.SoftDelete
=> nil
>>> tobin.IsActive
=> false

Note that I could also call tobin.soft_delete, IronRuby is translating .NET naming conventions into Ruby naming conventions, nice!

Finally, I now want to commit this unit of work, which will get NHibernate to do a Flush behind the scenes.

>>> UoW.Commit

If you have your NHibernate configured to spit SQL to the console, you'll see a ton of SQL being executed there.

5. Finally, a Bit of Ruby Fun

This one-liner loads all People and prints their names.

>>> UoW.Session.CreateQuery("from Person").method(:list).of(Person).call.each do |person| puts "#{person.FullName}: #{person.Email}" end
=> Tobin Harris: tobin@engineroomapps.com
   Chris Owen: chris@engineroomapps.com

Enjoy!


You may also like...