views:

570

answers:

4

I'm new to NHibernate (and ORMS) and trying to come to grips with the myriad of different options it presents. For reference, I'm using Fluent NHibernate with seperate business objects which in turn use DTO's purely for data access. My application architecture must support both windows and web "front ends".

My quandry is one of general approach as there seem to be so many options. My DTO's look something like the sample below. Each DTO has a reference to an ISession which is passed to them from the BO. They are responsible for their own load and save:

public class EmployeeDTO...

    // Data Properties to be persisted to the database
    public virtual int Id { get; private set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual ISession Session { get; set; }

    // Save logic
    public virtual void Save()
    {
        var transaction = Session.BeginTransaction();
        Session.SaveOrUpdate(this);
        transaction.Commit();
    }

    // Load logic
    public virtual void Load(int id)...

First of all: Is this the correct approach to take - should the DTO have the ability to save and load itself?

Secondly: Regardless of where the save/load code lies, should you use the same ISession for the lifetime or an object, or should they have a ref to the ISessionFactory and open a new session every time database interaction is required?

    // Open a new session every time I interact with the repository
    var session = FluentSupport.SessionFactory.OpenSession();
    var transaction = Session.BeginTransaction();
    Session.SaveOrUpdate(this);
    transaction.Commit();
    session.Close();
    // Close the session when I'm done

Of course there's always option 3, none of the above :)

+3  A: 

In general, DTOs do not contain behavior (like Save, Load) and do not contain knowledge of how they get persisted (ISession). It sounds like what you are really creating is a data layer. Your business layer ideally shouldn't know about ISession either. That said, you can shortcut this layering all you want as it fits your needs, but it will likely be difficult to change to a different ORM later if your ORM bleeds through all your layers.

For ISession lifetime management, you have to decide if you are going to use the UnitOfWork pattern, which basically says every user request gets a new ISession. There are other options for ISession lifetime as well and you really aren't limited in that regard. Often, there may be best practices around web apps vs. windows apps vs. whatever other application types, but you didn't specify which you were writing.

Michael Maddox
the architecure has to support both web (Silverlight) and windows (WPF)
Steve
I have clarified the question in order to cover this...
Steve
+1  A: 

The ISession is very inexpensive to open/close. The problem with keeping it open for too long is that the connection pool can't reuse the connection until it times out or what not. This could be a problem in a multiuser application.

In your scenario I'd probably go for a service oriented approach to store retrieve data. meaning the DTO would only be used internally within the service boundaries. If you need to copy objects that look the same I suggest you have a look at AutoMapper which was created for this specific purpose. If you have a windows only or web only project then it's not a problem. It's when you mix. You can't handle the sessions the same way in a Windows app as in a Web app.

mhenrixon
+4  A: 

Keep your loading/saving code separate from your DTOs. The DTO objects are only views of the underlying data.

When doing your queries, return the DTOs by using a transformation. Something like this:

resultSet = session.CreateCriteria(typeof(MyDataObject))
    .Add(query criteria, etc.)
    .SetResultTransformer(Transformers.AliasToBean<MyDTOObject>())
    .List<IMyDTOObject>()
Jon Seigel
+2  A: 

DTO's are meant to be "data transfer objects". That is, dumb objects used for passing values or collections of values around in your system. They shouldn't be responsible for persisting themselves, or even map 1-1 to domain objects in your domain layer.

jacko