2015-06-10 6 views
1

Я нахожусь в проекте, который использует последнюю Spring + Hibernate для настойчивости и для реализации REST API. Различные таблицы в базе данных содержат множество записей, которые в свою очередь также довольно большие. Итак, я создал много DAO для получения разных уровней детализации и их сопровождающих DTO.DTO с разной степенью детализации

Например, если у меня есть таблица Employee в базе данных, которая содержит тонны информации о каждом сотруднике. И если я знаю, что любой клиент, использующий мое приложение, очень выиграет от получения разных уровней детализации сущности Employee (вместо того, чтобы каждый раз обстреливать весь объект), то, что я делал до сих пор, выглядит примерно так:

class EmployeeL1DetailsDto 
{ 
    String id; 
    String firstName; 
    String lastName; 
} 

class EmployeeL2DetailsDto extends EmployeeL1DetailsDto 
{ 
    Position position; 
    Department department; 
    PhoneNumber workPhoneNumber; 
    Address workAddress; 
} 

class EmployeeL3DetailsDto extends EmployeeL2DetailsDto 
{ 
    int yearsOfService; 
    PhoneNumber homePhoneNumber; 
    Address homeAddress; 
    BidDecimal salary; 
} 

и так далее ...

Здесь вы видите, что я разделил информацию сотрудника на различных уровнях детализации. Сопроводительный DAO будет выглядеть примерно так:

class EmployeeDao 
{ 
    ... 

    public List<EmployeeL1DetailsDto> getEmployeeL1Detail() 
    { 
     ... 
     // uses a criteria-select query to retrieve only L1 columns 
     return list; 
    } 

    public List<EmployeeL2DetailsDto> getEmployeeL2Detail() 
    { 
     ... 
     // uses a criteria-select query to retrieve only L1+L2 columns 
     return list; 
    } 

    public List<EmployeeL3DetailsDto> getEmployeeL3Detail() 
    { 
     ... 
     // uses a criteria-select query to retrieve only L1+L2+L3 columns 
     return list; 
    } 

    . 
    . 
    . 
    // And so on 
} 

Я использую Hibernate в aliasToBean() для автоматического отображения извлеченных сущностей в DTOS. Тем не менее, я чувствую, что количество котельной пластины в процессе в целом (все DTO, методы DAO, параметры URL для желаемого уровня детализации и т. Д.) Немного беспокоят и заставляют меня думать, что может быть более чистый подход к этому.

Итак, мой вопрос: есть ли лучший шаблон для получения разных уровней детализации из сохраняемого объекта? Я довольно новичок в Spring и Hibernate, поэтому не стесняйтесь указывать что-либо, что считается базовым знанием, которое, по вашему мнению, я не знаю.

Спасибо!

+1

Можете ли вы предоставить подробную информацию о том, почему вы wamt ограничиваете детали? Безопасность, производительность, ...? – Maze

+0

Главным образом для производительности и немного для обеспечения безопасности (уменьшение видимости конфиденциальных данных, возвращаемых на менее привилегированные вызовы службы). Но да, моя главная забота - это производительность. – user623941

ответ

1

Я бы выбрал как можно меньше различных запросов. Я предпочел бы, чтобы ассоциации были ленивыми в моих сопоставлениях, а затем позволяли им инициализироваться по требованию с помощью соответствующих стратегий выборки Hibernate.

Я думаю, что нет ничего плохого в том, что у каждого класса бизнес-модели есть несколько разных классов DTO и что они часто делают код более читабельным и поддерживаемым.

Однако, если количество классов DTO имеет тенденцию взорваться, тогда я бы сделал баланс между читабельностью (ремонтопригодностью) и производительностью.

Например, если поле DTO не используется в контексте, я бы оставил его как null или заполнил его в любом случае, если это действительно не дорого. Тогда, если это значение равно null, вы можете указать маршаллеру объекта исключить пустые поля при получении ответа службы REST (JSON, XML и т. Д.), Если это действительно беспокоит потребителя услуги. Или, если вы его заполняете, то это всегда приветствуется позже, когда вы добавляете новые функции в приложение и начинаете использовать его в контексте.

+0

Спасибо. Я думаю, что я пойду с этим, сделав маршаллера исключительным. Таким образом я оставлю ненужные свойства. Они довольно малы по размеру, по сравнению с тем, когда они заполнены, но все еще раздражают, чтобы увидеть 50 или более нулевых свойств для каждой записи. – user623941

1

Вам необходимо будет определить в той или иной степени разные версии гранулярности. Вы можете попробовать иметь подобъекты, которые не загружены/установлены в нуль (как рекомендовано в других ответах), но это может легко стать довольно неудобным, поскольку вы начнете структурировать свои данные по соображениям безопасности, а не по модели домена. Так что делать это с отдельными классами - ведь это не такой уж плохой подход.

Возможно, вы захотите сделать его более динамичным (возможно, потому, что вы хотите расширить даже свою модель данных на стороне db с большим количеством данных).

Если это так, вы можете перенести определение из кода на некоторые конфигурации (может даже быть динамическим во время выполнения). Разумеется, это потребует также динамической модели данных на стороне Java, например, с использованием хэш-карты (см. here о том, как это сделать). Таким образом, вы получаете динамическую модель данных, но теряете безопасность типов (по крайней мере, до определенной степени). На других языках, которые, вероятно, будут чувствовать себя естественными, но в Java это менее распространено.

Теперь вы должны определить, как вы хотите заполнить свой объект, своим HQL. Путь, который вы хотите принять, в настоящее время зависит от контекста, как ваш объект будет использоваться

0

Другой подход заключается в использовании только объектов домена на уровне Дао и определении необходимых подмножеств информации как DTO для каждого использования. Затем конвертируйте сущность Employee в каждый DTO с помощью универсального конвертера DTO, как я использовал в последнее время в своих профессиональных мероприятиях Spring. MIT-лицензированный модуль доступен в артефакте dtoconverter репозитория Maven. и далее информация и руководство пользователя на автора Wiki:

http://ratamaa.fi/trac/dtoconverter

Quickest идея, которую вы получите из примера страницы там:

раздолье ...

0

Blaze-Persistence Entity Views были созданы для точно таких прецедент. Вы определяете структуру DTO как интерфейс или абстрактный класс и имеете сопоставления с атрибутами вашего объекта. При запросе вы просто проходите в классе, и библиотека позаботится о создании оптимизированного запроса для проекции.

Вот краткий пример

@EntityView(Cat.class) 
public interface CatView { 
    @IdMapping("id") 
    Integer getId(); 

    String getName(); 
} 

CatView является определение DTO и здесь приходит опрашивающего Часть

CriteriaBuilder<Cat> cb = criteriaBuilderFactory.create(entityManager, Cat.class); 
cb.from(Cat.class, "theCat") 
    .where("father").isNotNull() 
    .where("mother").isNotNull(); 

EntityViewSetting<CatView, CriteriaBuilder<CatView>> setting = EntityViewSetting.create(CatView.class); 
List<CatView> list = entityViewManager 
         .applySetting(setting, cb) 
         .getResultList(); 

Следует отметить, что существенная часть является то, что EntityViewSetting имеет CatView типа который применяется к существующему запросу. Созданный JPQL/HQL оптимизирован для CatView, т. Е. Он только выбирает (и присоединяется!) То, что ему действительно нужно.

SELECT 
    theCat.id, 
    theCat.name 
FROM 
    Cat theCat 
WHERE theCat.father IS NOT NULL 
    AND theCat.mother IS NOT NULL 
Смежные вопросы