Возможно ли иметь неизменяемые объекты JPA? - PullRequest
15 голосов
/ 30 декабря 2010

В нашем проекте hibernate сущности кодируются с использованием шаблона Java-бинов. В нашем коде довольно много мест, где кто-то забыл установить мутатор, и мы получаем исключение из-за поля NOT NULL.

Кто-нибудь использует строителя для создания своих сущностей или делает их неизменными?

Я пытаюсь найти эффективный шаблон, который не соответствует стилю шаблона Java-бобов.

Спасибо

Ответы [ 3 ]

14 голосов
/ 30 декабря 2010

Если вы делаете ваши bean-компоненты неизменяемыми, тогда вы должны использовать доступ на уровне поля, и это сопровождается собственным набором проблем, которые подробно обсуждаются здесь . Подход, который мы выбрали, заключается в том, чтобы у Строителя / Фабрики были соблюдение / проверка требований и т.д. для нас.

10 голосов
/ 09 декабря 2015

В нашем проекте мы используем подход vanilla builders (@see Effective Java). Рассмотрим следующий пример:

@Entity
public class Person {
   public static class Builder {
        private String firstName;
        private String lastName;
        private PhoneNumber phone;

        public Builder() {}

        public Builder withFullName(String fullName) {
            Preconditions.notNull(fullName); 
            String[] split = fullName.split(" ");
            if (split == null || split.length != 2) {
                throw new IllegalArgumentException("Full name should contain First name and Last name. Full name: " + fullName);
            }  
            this.firstName = split[0];
            this.lastName = split[1];
            return this;
        }

        public Builder withPhone(String phone) {
            // valueOf does validation
            this.phone = PhoneNumber.valueOf(phone);
            return this;
        }

        public Person build() {
            return new Person(this);
        }
   }

   //@Columns
   private long id;//@Id
   private String firstName;
   private String lastName;
   private String phoneNumber;

   // hibernate requires default constructor
   private Person() {} 

   private Person(Builder builder) {
       this.firstName = Preconditions.notNull(builder.firstName);
       this.lastName = Preconditions.notNull(builder.lastName);
       this.phoneNumber = builder.phone != null ? builder.phone : null;
   }

   //Getters
   @Nonnull
   public String getFirstName() { return firstName;}
   @Nonnull
   public String getLastName() { return lastName;}
   @Nullable
   public String getPhoneName() { return phone;}
   public long getId() { return id;}
}

На случай, если вы захотите иногда видоизменить объект, я рекомендую ввести new Builder(Person person), который скопирует все данные обратно, чтобы вы могли преобразовать его с помощью компоновщика. Конечно, он создаст новую сущность, поэтому старая останется только для чтения.

Использование (с мутацией) так же просто, как:

Person.Builder personBuilder = new Person.Builder();
Person person = personBuilder.withFullName("Vadim Kirilchuk").withPhone("12345678").build();

Person modified = new Person.Builder(person).withPhone("987654321").build();

Также важно отметить, что в этом примере Person не является на 100% неизменным (и не может быть) классом: прежде всего потому, что jpa устанавливает id , также могут быть ленивые ассоциации извлекается во время выполнения и, наконец, потому что у вас не может быть полей final (из-за необходимого конструктора по умолчанию) :( Последний момент также относится к многопоточным средам, то есть возможно, что сущность, переданная в другой поток сразу после привести к всевозможным ошибкам, так как другой поток не гарантирует увидеть полностью построенный объект.

Спецификация JPA 2.1, раздел «2.1. Класс сущности», гласит:

Запрещается использование методов или постоянных переменных экземпляра класса сущностей. окончательный.

Еще один похожий подход: http://vlkan.com/blog/post/2015/03/21/immutable-persistence/

В моем случае я бы просто добавил id для строителя, а не создавал службу поверх черновиков ..

0 голосов
/ 06 июня 2019

@Immutable аннотация может быть использована на Entity. JPA будет игнорировать все обновления, сделанные для объекта.

https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/Immutable.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...