2014-01-07 4 views
16

Я ищу хороший способ создания объектов передачи данных (DTO) из сущности JPA и наоборот. Я хочу отправить DTO как JSON клиенту, а затем получить измененный DTO и сохранить его обратно в базу данных. Было бы наиболее легко выполнить метод слияния из EntityManager на полученном объекте после того, как он был разобран JSON на его класс Java.Образец для JPA: создание объекта передачи данных DTO из объекта и слияние DTO с базой данных

Например, есть следующее Entity и метод Rest для сохранения измененного объекта:


@Entity 
@Table(name="CUSTOMER") 
public class Customer { 
    @Id 
    Long id; 
    @Version 
    Long version; 
    String name; 
    String address; 
    String login; 
    String password; 
    String creditCardNumber; 
    @OneToMany(cascade = CascadeType.ALL) 
    List<Foo> fooList; 

    ... Getter() and Setter() 
} 

private EntityManager em; 
@POST 
@Path("/saveCustomer") 
public void saveCustomer (Customer customer) {    
    em.merge(customer); 
    return; 
} 

Это прекрасно работает до тех пор, как я отправить весь Entity класс, как JSON и получить весь Entity назад. Затем EntityManager объединит модифицированный объект с базой данных. Но когда я только хочу, чтобы обеспечить подмножество Entity (например, только имя и адрес клиента) будут проблемы:

  1. Что бы лучший способ создать подмножество Субъект?

    -Напишите DTO для сущности вручную? Это создаст повторяющийся код для каждого подмножества объекта, который должен поддерживаться.

  2. Как объединить DTO, который является подмножеством объекта, обратно в базу данных?

    -Использование метода merge() EntityManager не работает. Сначала DTO не является субъектом, поэтому его нельзя объединить. И только создание объекта из DTO будет иметь некоторые неустановленные значения в Entity. После слияния значения будут иметь значение NULL в базе данных.


Одна идея, которую я придумал, был указать дополнительные объекты для каждого подмножества Я хочу иметь для субъекта. (Подобно представлению базы данных) Это будет дублированный код, но он может решить проблему с объединением DTO в базу данных. (И, возможно, этот код может быть сгенерирован автоматически)

Например, Entity CustomerView1 ссылается на ту же таблицу, что и класс Customer, но предоставляет только имя и адрес клиента. Это DTO для реального класса Customer, который может быть отправлен как JSON и изменен вне сервера. Этот класс также может быть объединен с базой данных EntityManager.

@Entity 
@Table(name="CUSTOMER") 
public class CustomerView1 { 
    @Id 
    Long id; 
    @Version 
    Long version; 
    String name; 
    String address; 
     
        ... Getter() and Setter() 
}     

Но у меня есть сомнения по поводу этого решения, я не знаю, если это будет беспорядок с кэшированием в JPA о Entities и может вызвать некоторые проблемы.


Мой вопрос, есть ли шаблон для решения дублирования кода для DTOS и объединений DTOs обратно в базу данных?

Или есть библиотека для этой цели? - Что-то вроде автогенерации для DTO и копирования DTO обратно в реальную Entity, чтобы объединить их с EntityManager.

+1

Чтобы сохранить некоторые строки кода, вы можете использовать библиотеку apache commons-BeanUtils. Взгляните сюда http://commons.apache.org/proper/commons-beanutils/apidocs/org/apache/commons/beanutils/BeanUtils.html В нем есть утилиты-методы, которые копируют свойства из/в pojo с отражением. – gipinani

ответ

1

Посмотрите на шаблон дизайна объекта Value, который непосредственно решает вашу проблему.

Этот учебник дает хорошее введение в объекты ценности.

http://www.javastuff.in/2012/04/value-object-pattern.html

+3

. означает нечто иное, чем описано в связанной статье. Хотя эти термины не кодифицированы, лучше следовать основному потоку. Например. см. http://www.adam-bien.com/roller/abien/entry/value_object_vs_data_transfer – xmedeko

+0

Thx для вашего комментария +1 – Diversity

4

Если разница в размерах между объектом и DTO не значительна, вы можете выбрать для отправки Субъекта.

При использовании DTO, чтобы преодолеть проблемы параллелизма, такие как lost update, вам необходимо включить версию сущности в ваш DTO.

Если вы не используете версию Entity, а базовая строка будет изменена между методами REST GET и PUT, вы переопределите изменения, о которых конечный пользователь не знал.

Всякий раз, когда мне приходится изменять сущность (создавать, обновлять, удалять), я полагаюсь на JPA and Hibernate Optimistic Locking mechanism.

Для списков пользователей, таблиц, результатов поиска DTO являются жизнеспособным вариантом, поскольку вас интересует только проекция вашего исходного объекта. Таким образом, вы ускоряете извлечение, и вы можете воспользоваться другими функциями SQL (оконными функциями), которые не поддерживаются JPA.

+1

Иногда отправка всей сущности и ее слияние могут быть опасными. Представьте себе объект клиента, который имеет такие поля, как createDate или login, которые не предназначены для модификации на этом конкретном экране (но они не определены как readonly на сущности). Если весь объект отправлен как JSON, а затем получен обратно и объединен(), как вы можете гарантировать, что только соответствующие поля были изменены? В таком случае (который, я думаю, довольно распространен), оригинальное решение с представлением сущности кажется более подходящим, не так ли? И @Version защищает от потерянных обновлений, нет? – Lucian

+1

Вы можете установить updatable = false для этих атрибутов –

0

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

Смежные вопросы