José F. Romaniello

Las aventuras y desventuras de un codificador.


Part I: Introducing NHiberate and WPF: The ChinookMediaManager

Introduction


This is my second post about the Chinook Media Manager, an example application for NHibernate and WPF. In this post I will outline some concepts behind the architecture that I’ve chosen.

Note

Probably at some points you will feel that this is over-architected, YAGNI and so on. Yes, you are right I’m not trying to bind a grid to a collection of objects there are tons of samples on the net about that subject.

The four musketeers

The core of the application is composed of four components:

  • ChinookMediaManager.Data: Contains the definition of repositories interfaces.
  • ChinookMediaManager.DataImpl: Contains the implementation of these repositories plus other nhibernate things that we will need to make work the implementation of repositories (like mappings).
  • ChinookMediaManager.Domain: Contains the domain classes plus model interfaces (we will focus on this concept latter)
  • ChinookMediaManager.DomainImpl: Contains the implementation of the models.

My base repository definition is as follows:

public interface IRepository<T> : IQueryable<T>
{
    T Get(object id);
    T Load(object id);
    T MakePersistent(T entity);
    void Refresh(T entity);
    void MakeTransient(T entity);
}

This means that a repository is a IQueryable<T> by itself and we can build queries in a more natural way.
I have seen a lot of repositories implementations with methods Save, Update and Delete, there is nothing wrong with it, just that I think that MakePersistent (Save) and MakeTransient (Delete) better represents that functionality (I have stolen this terminology from a Gustavo Ringel’s example).
You could find the implementation here.

Don’t touch “the domain”

Working with WPF sometimes you will need that your entities implement INotifyPropertyChanged or IEditableObject for data binding. Although the implementation of those interfaces is simple, if you implement directly in your domain you will tie your domain to a presentation concern and also will end writing a lot of code.

So, I wrote an addin for nhibernate (unhaddins.wpf) that will help you to inject those behaviors without touching anything in your domain model. 

We only have to add the entity to the container as follows:

container.Register(Component.For<Album>()
    .NhibernateEntity()
    .AddNotificableBehavior()
    .LifeStyle.Transient);

If you need to add editable object behavior (read this and this) you simple put “.AddEditableBehavior()”.
If we want a transient instance we will request it to the container (or an object factory). In unhaddins we have got an artifact that allows nhibernate to instantiate entities from the container, read this post from Fabio Maulo.

For INotifyCollectionChanged, unhaddins.wpf has a Collection Type Factory, we need to configure NHibernate as follows:

nhConfiguration.Properties[Environment.CollectionTypeFactoryClass] =
  typeof (WpfCollectionTypeFactory).AssemblyQualifiedName;

With this simple step all bag, sets and list (more coming up) of objects retrieved from NHibernate will implement INotifyCollectionChanged.

It goes without saying that this configuration is not in the domain.

As you can see, I don’t have to put presentations concerns inside “the four musketeers”.

In the next post I will talk about models and CpBT.

| More

7 comentarios:

Hi José, how are you doing?
I've been following your blog from some time ago... very interesting posts lately.

I've a question about this one:

I usually architecture my solutions using 2 core projects: Project.Core (your Domain + Data + DomainImpl) and Project.Data (your DataImpl).
I understand that isolating the DataImpl funcionality you delimit where NH is used, but... what do you gain by having the other components splitted between 3 different projects?

Kind regards.

Hi German, Your architecture is very good. I split Domain and DomainImpl because DomainImpl contains a concrete implementation of a Model class that represents my use-case and since we can change a repository implementation (because we have Data for interfaces and DataImpl for concrete), we also can change the implementation of a Model class. I will talk about this concept in my next post.

German.
I think José is following the "best practices" of uNhAddIns where, even if we love NH, we are designing our examples as though NH is only an option.

Hi Jose,

Great series of articles, keep it up. Is there a link to a zip containg the sample code, or do I have to get the SVN trunk?

Thanks.

Sorry for the delay, there is not a zip. You need to download from the trunk of unhaddins/examples.

Hi José,

And thank you for a great blog, I've been reading more and more of your stuff lately since I'm in the startup of a project that is using NHibernate and WPF (and Prism).

I've tried to get this to work with the auto mapping feature of Fluent NHibernate. I set the CollectionTypeFactoryClass property, but the automappings don't use it. Do you know if there is anything I can do to get this to work with Fluent NHibernate? Thank you!

José F. Romaniello dijo...

<span style="color: #808080;">Hi, glad to hear you. Please follow this thread in the FNH forum.</span>

Publicar un comentario en la entrada