0

I seperate my domain logic from my web service logic

This is from my domain and actually gets the data from nHibernate

public static IList<Location> LoadReturnLocationsFromDatabase(DateTime lastUpdateTime)
{
    using (var session = NHibernateHelper.OpenSession())
    {
        // retreive all stores and display them
        using (session.BeginTransaction())
        {
            var locations = session.CreateCriteria(typeof(Location)).Add(Expression.Gt("LastUpdatedTime", lastUpdateTime)).SetMaxResults(10).List<Location>();
            return locations;
        }
    }
}

This data is then returned to the web service and I use Automapper to duplicate it, so as to not expose the database access object to the web service and keep all things seperate.

public IList<GetLocationDetailsResponse> GetLocationUpdate(DateTime lastUpdateTimeDT)
{

    Mapper.CreateMap<Location, GetLocationDetailsResponse>();

    IList<Location> locations = WhygoDomain.GetLocations.LoadReturnLocationsFromDatabase(lastUpdateTimeDT);

    IList<GetLocationDetailsResponse> getLocationDetails = Mapper.Map<IList<Location>, IList<GetLocationDetailsResponse>>(locations);
    return getLocationDetails;
}

My problem is that I can't do the mapping unless I specify that the relationship between location and state isn't lazy loaded because the web service is outside:

using (var session = NHibernateHelper.OpenSession())

in the data domain.

Lazy loading does seem to be the prefered method of doing something like this, so I'm wondering if this approach ok? This is a data export service which will export so memory usage etc could end up being problematic.

If I need to change this, is the cause of the problem the structure of my code? If so how can I keep my domain logic seperate, and get around this problem?

1
  • Do you have an AOP framework in place? Commented Jan 24, 2012 at 11:52

2 Answers 2

2

Eager Fetch

You can avoid this problem and achieve better performance by eagerly fetching the states along with the locations - otherwise you have what's called a "Select N+1" problem. See Ayende's blog for a good explanation of this: http://ayende.com/blog/1328/combating-the-select-n-1-problem-in-nhibernate.

Essentially, a separate SQL query is executed every time a different location.State is accessed, which could mean as many as 11 round-trips to the database in your case. If the location query included the states in a LEFT OUTER JOIN, then all of the needed data could be fetched in a single round-trip to the database.

In your case, the following query will probably work better:

var locations = session.CreateCriteria(typeof(Location))
    .Add(Expression.Gt("LastUpdatedTime", lastUpdateTime))
    .SetMaxResults(10)
    .SetFetchMode("State", FetchMode.Eager)
    .List<Location>();

Dependency Inversion

The problem you have encountered illuminates the fact that GetLocations does not know enough about the situation to be responsible for creating and destroying NHibernate Sessions. The creation of the NHibernate Session needs to be moved up at least one layer. There are certainly more elegant ways of doing all of this, like using an IoC container, but here's some quick and dirty code to illustrate what I mean:

public IList<GetLocationDetailsResponse> GetLocationUpdate(DateTime lastUpdateTimeDT)
{
    using (var session = NHibernateHelper.OpenSession())
    {
        var locations = GetLocations.LoadReturnLocationsFromDatabase(session, lastUpdateTimeDT);
        return Mapper.Map<IList<Location>, IList<GetLocationDetailsResponse>>(locations);
    }
}

One final note: AutoMapper's Mapper.CreateMap is static setup code that only needs to be executed once on application start. Global.asax is the best place for that type of code.

Sign up to request clarification or add additional context in comments.

Comments

2

As you need an open session to be able to map from the attached domain object to the detached auto mapped object, you will have to ensure that the session is open while you are automapping. You could consider moving your using statement up to the web service call rather than having it within the domain method.

4 Comments

I know what you're saying, but that seems to get rid of the whole point of seperating the web service and the domain... Maybe I have over seperated it already though...
I wonder would this be preferable to not lazy loading the data
@iKode: It doesn't make any sense to lazy load the data if you access all of its property directly after loading it anyway.
@Daniel. Yes, he could eager fetch if the data he was looking for always needed to be hydrated any time the top level entity was touched. Depends on the use case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.