使用nHibernate Fluent,Web服务和automapper进行延迟加载

时间:2012-01-24 11:48:55

标签: c# nhibernate fluent-nhibernate automapper

我从我的网络服务逻辑中分离我的域逻辑

这是来自 my domain ,实际上是从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;
        }
    }
}

然后将此数据返回到 Web服务,并使用Automapper将其复制,以便不将数据库访问对象公开给Web服务并保持所有内容分离。

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;
}

我的问题是我无法进行映射,除非我指定位置和状态之间的关系没有延迟加载,因为Web服务在外面:

using (var session = NHibernateHelper.OpenSession())

在数据域中。

延迟加载似乎是做这样的事情的首选方法,所以我想知道这种方法是否正常?这是一个数据导出服务,将导出,因此内存使用等可能最终成为问题。

如果我需要更改此问题,问题的原因是我的代码结构?如果是这样,我如何保持我的域逻辑分离,并解决这个问题?

1 个答案:

答案 0 :(得分:2)

渴望获取

您可以通过急切地获取状态以及位置来避免此问题实现更好的性能 - 否则您会遇到所谓的“选择N + 1”问题。有关此问题的详细解释,请参阅Ayende的博客: http://ayende.com/blog/1328/combating-the-select-n-1-problem-in-nhibernate

基本上,每次访问不同的location.State时都会执行单独的SQL查询,这可能意味着在您的情况下,最多可以对数据库进行11次往返。如果位置查询包含LEFT OUTER JOIN中的状态,则可以在数据库的单次往返中获取所有需要的数据。

在您的情况下,以下查询可能会更好:

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

依赖性倒置

你遇到的问题说明GetLocations对于创建和销毁NHibernate Sessions负责的情况不够了解这一事实。 NHibernate会话的创建需要至少向上移动一层。当然有更优雅的方法来完成所有这些,比如使用IoC容器,但是这里有一些快速而脏的代码来说明我的意思:

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);
    }
}

最后一点:AutoMapper的Mapper.CreateMap是静态设置代码,只需要在应用程序启动时执行一次。 Global.asax是这类代码的最佳位置。