Monday, July 11, 2011

NHibernate cascading styles + ConfOrm = Iguazu Falls!

Alright! So let's get down and dirty with my first "real" blog post, shall we?

For those who don't know about ConfOrm, let me say that he is the smartest guy in town when mapping domain entities is all about (besides Fabio Maulo, of course, who is responsible for it as well as being NHibernate's project leader :-) ).

you can read all about it here:

If there is an ideology hidden in this post, that would be to prove yet again that you can use ConfOrm to "auto-map" almost any mapping scenario you can think of, no matter how complex your scenario is.

I have this domain that has lots and lots and lots of entities that map to a single one. Even this entity maps to itself.

Most of the associations are the same: many-to-one. But as well this domain makes use of a many-to-many, and a peculiar many-to-any association (more on this domain in the following posts).

Irrespective of the association used, all of them share one thing in common: the association's target entity. And even if you don't know the actual mapping, you can guess that if everything points to a single thing, then that thing sort of defines the rules of the game.

Now, while ConfOrm provides many "patterns" to set cascadings based on the association type of a mapping, it does not provide a way to set cascading styles based on given types, more specifically, the target of the association.

That being said, what ConfOrm DOES provide is a way to define your own patterns, and that is what makes it so useful: you define your conventions (plus all the gems in ConfOrm.Shop) and this guy takes care of the rest! You do have to hand-code the "exceptions" to the rules yourself, but that's what they are, exceptions.

So you get the usual "mapping-by-code" benefits that you get with tools like Fluent NHibernate, and your mapping code reduces a lot. But more important than that is that you can make your domain grow without having to revisit over and over again your mappings.

Ok, I just realised that I wrote too much already and didn't show anything to prove what I'm saying! So here you go:

   1:      /// <summary>
   2:      /// Pattern to create a general cascading rule where the target of the
   3:      /// association is of type T.
   4:      /// </summary>
   5:      /// <typeparam name="TMatch">A type to use as a target match.</typeparam>
   6:      public class DefaultCascadingForTargetPattern<TMatch> :
   7:      IPatternValueGetter<Relation, Cascade?>
   8:      {
  10:          private readonly Cascade _cascade;
  12:          public DefaultCascadingForTargetPattern(Cascade cascade)
  13:          {
  15:              _cascade = cascade;
  17:          }
  19:          /// <summary>
  20:          /// Determines if the target type of a relation (subject.To) matches the
  21:          /// type TMatch.
  22:          /// </summary>
  23:          public bool Match(Relation subject)
  24:          {
  26:              return ReferenceEquals(subject.To, typeof(TMatch));
  28:          }
  30:          /// <summary>
  31:          /// Returns the cascading style to be used.
  32:          /// </summary>
  33:          public Cascade? Get(Relation subject)
  34:          {
  36:              return _cascade;
  38:          }
  40:      }

And you can use this pattern like this:

var orm = new ObjectRelationalMapper(); 
new DefaultCascadingForTargetPattern<YourEntityHere>(Cascade.Persist)

Simple, huh!

Do let me know what you think!

No comments:

Post a Comment