Jan Limpens

31. 08. 2008

Handling Collections with NHibernate

Filed under: development — Tags: , , — admin @ 11:17

When business entities hold some collection and you read the NHibernate manual on how to handle this, most parts of the book (not all) will either tell you to expose this either as an IList (more pragmatic) or as an ISet (more beautiful, performant, failsafe, etc.).

I am under the impression that it generally is a bad idea to expose any type of collection that way. Why?

(I go with IList here, but same applies to any other collection)

case 1)

class Bar {
    public Foo Parent {get;set;}
}

class Foo {
    public IList<Bar> Bars {get; set;}
}

Now you are completely exposed. Anyone who has to handle this code, must be conscious of any side effects this may have. For instance, if you have a bidirectional relation to handle you must code like that, or you’ll get an error:

var bar = new Bar();
var foo = new Foo();
bar.Foo = foo;
foo.Bars = new List<Bar>();
foo.Bars.Add(bar);

Quite a bit of code that will repeat over and over in your app. My verdict: avoid this! Many people go with something slightly better:

2) Shielded and somewhat correct

class Foo {
    IList bars<Bar> = new List<Bar>();

    public IList<Bar> Bars {
        get { return new List<Bar>(bars).AsReadonly; }
        private set { bars = value; }
    }

    public void AddBar(Bar bar){
        // set whatever is necessary to keep consistence and let the user forget
        // about persistence details like bidirectionality
    }
}

If you unit test this, your tests will be green and you will be shielded against mistakes. You can forget the inner workings and everything will be fine. That is, unless you want to load this collection lazily (and receive lots of performance benefits). I actually already forgot what the concrete problem was, but it seems, that NHibernate inspects, what Bars delivered and tries to give the same back using the private setter. It got a ReadOnlyCollection, so it tries to set one. And this fails somehow. (I’ll try to come up with the original error). So you either return bars directly and leave two possible ways to access it, one that works, and one that sometimes works. Horror. Or. you go, by what I do right now.

3) Shielded

class Foo {
    private ISet<Bar> barSet;

    public ReadOnlyCollection<Bar> Bars {
        get {return new List<Bar>(barSet); }
    }

    public void AddBar()Bar bar {
        // add a bar
    }
}

This

  1. uses the NHibernatewise better performing Set, that most possibly also represents much better your idea of what should be returned.
  2. returns a shielded IList, that has the foreach semantics you were looking for (ISet has not)
  3. Shields you from future mistakes

Mind: You map against bars using a <set/> tag. This is a very basic pattern, but I thought, if you are new to it, it might give you a better start. I did not find this documented anywhere.

Getting GCompris to run in Mac Os X

Filed under: development, misc — Tags: , , , — admin @ 8:56

My kiddo liked to play with GCompris, a quite nice (although none of them are as nice as I would wish they were) application suite for children. I had it running on my windows pc, but when I switched it to a mac mini (I just loved the silence), this was gone.

After a quick google for “GCompris Mac” quickly revealed a fink info page, I knew I had to go the fink route. I nstalled, find and fink commander and… nothing, no gcompris. I rechecked the page –> unstable. So I reconfigured fink to accept unstable branches, but nothing. These unstable branches never seemed to arrive.

So I left it at there. Yesterday I gave it a new try. On the fink faq I found an entry explaining how to install something on an unstable branch, without actually configuring fink to go completely unstable. Sounded quite like the thing I needed.

So I ran fink selfupdate-cvs and it seemed to pull down halve of the world (via cvs). After a while unstable brances seemed to appear and even the looked for GCompris entry. Victory!

So after I did fink selfupdate; fink index; fink scanpackages. I ran sudo fink install gcompris, it again started to download half of sourceforge to fulfill it’s dependencies. First build failed, I had to pull and build a library (don’t remember which) because fink “got confused”. Now I am during the second try and it seems to build even kde and enlightenment and whatever. Seems the dependencies are huge.

Other kids software I think is nice:

Powered by WordPress