Мързеливо зареждане с nHibernate Fluent, уеб услуги и automapper

Разделям логиката на моя домейн от логиката на моята уеб услуга

Това е от моя домейн и всъщност получава данните от 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;
        }
    }
}

След това тези данни се връщат към уеб услугата и аз използвам Automapper, за да ги дублирам, така че да не излагам обекта за достъп до базата данни на уеб услугата и да запазя всички неща отделно.

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

Проблемът ми е, че не мога да направя картографирането, освен ако не уточня, че връзката между местоположение и състояние не е заредена лениво, тъй като уеб услугата е извън:

using (var session = NHibernateHelper.OpenSession())

в областта на данните.

Мързеливото зареждане изглежда е предпочитаният метод за правене на нещо подобно, така че се чудя дали този подход е добре? Това е услуга за експортиране на данни, която ще експортира, така че използването на паметта и т.н. може да се окаже проблематично.

Ако трябва да променя това, причината за проблема ли е структурата на моя код? Ако е така, как мога да запазя логиката на домейна си отделна и да заобиколя този проблем?


person iKode    schedule 24.01.2012    source източник
comment
Имате ли AOP рамка?   -  person Rich O'Kelly    schedule 24.01.2012


Отговори (2)


Нетърпеливо извличане

Можете да избегнете този проблем и да постигнете по-добра производителност, като нетърпеливо извличате състоянията заедно с местоположенията – в противен случай имате това, което се нарича проблем „Изберете N+1“. Вижте блога на Ayende за добро обяснение на това: http://ayende.com/blog/1328/combating-the-select-n-1-problem-in-nhibernate.

По същество отделна SQL заявка се изпълнява всеки път, когато се осъществи достъп до различен location.State, което може да означава до 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 Session трябва да бъде преместено нагоре с поне един слой. Със сигурност има по-елегантни начини да направите всичко това, като използването на 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);
    }
}

Една последна бележка: Mapper.CreateMap на AutoMapper е статичен код за настройка, който трябва да се изпълни само веднъж при стартиране на приложението. Global.asax е най-доброто място за този тип код.

person Daniel Schilling    schedule 24.01.2012

Тъй като се нуждаете от отворена сесия, за да можете да картографирате от прикачения домейн обект към отделения автоматично картографиран обект, ще трябва да се уверите, че сесията е отворена, докато извършвате автоматично картографиране. Бихте могли да помислите за преместване на израза за използване до извикването на уеб услугата, вместо да го поставите в метода на домейна.

person Nick Ryan    schedule 24.01.2012
comment
Знам какво казвате, но това изглежда премахва целия смисъл на разделянето на уеб услугата и домейна... Може би вече съм го разделил прекалено много... - person iKode; 24.01.2012
comment
Чудя се дали това е за предпочитане пред не мързеливото зареждане на данните - person iKode; 24.01.2012
comment
@iKode: Няма смисъл да зареждате данните на мързелив начин, ако така или иначе имате достъп до цялото им свойство директно след зареждането. - person Daniel Hilgarth; 24.01.2012
comment
@Даниел. Да, той можеше да извлича, ако данните, които търсеше, винаги трябваше да бъдат хидратирани всеки път, когато обектът от най-високо ниво беше докоснат. Зависи от случая на употреба. - person Nick Ryan; 24.01.2012