Hibernate копирует значения объекта в новый объект с новым сгенерированным идентификатором - PullRequest
25 голосов
/ 30 марта 2012

Я использую реляционную базу данных, используя один столбец pk с несколькими вложенными таблицами.Мне нужно добавить простое архивирование в мой проект.Архивация происходит только тогда, когда приложение достигает определенного состояния, поэтому я надеялся скопировать существующий объект hibernate в новый экземпляр, где новый экземпляр будет сохранен с новым идентификатором, при этом оставив существующий объект без изменений.Я не могу понять, как скопировать существующий объект в новый экземпляр без необходимости вручную устанавливать каждое новое поле экземпляра.Кто-нибудь знает простой способ сделать это?

Ответы [ 7 ]

36 голосов
/ 17 апреля 2013

Просто извлеките объект, отсоедините его, установите идентификатор на ноль и сохраните его.

MyEntity clone = entityManager.find(MyEntity.class, ID);
entityManager.detach(clone);
clone.setId(null);
entityManager.persist(clone);

Если у вашего объекта есть отношения oneToMany, вам придется повторить операцию для всех дочерних элементов, но вместо идентификатора null установить идентификатор родительского объекта (генерируется после вызова persist).

Конечно, вам придется удалить все CASCADE persist в ваших отношениях OneToMany, так как в противном случае ваш постоянный вызов создаст дубликаты всех дочерних элементов в ошибках DB или fk.

6 голосов
/ 30 марта 2012

Я также работаю с Hibernate и получил то же требование, что и вы. Я следовал за реализацией Cloneable. Ниже приведен пример кода, как это сделать.

class Person implements Cloneable {

        private String firstName;
        private String lastName;

        public Object clone() {

            Person obj = new Person();
            obj.setFirstName(this.firstName);
            obj.setLastName(this.lastName);

            return obj;
        }

        public String getFirstName() {
            return firstName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    }

Или вы можете перейти к решению на основе отражения, но я не буду этого рекомендовать. Проверьте этот веб-сайт для более подробной информации.

3 голосов
/ 29 мая 2015

Посмотрите на следующую ссылку.один из самых мощных механизмов клонирования, который можно наиболее эффективно использовать с Hibernate

http://thoughtfulsoftware.blogspot.in/2013/05/using-variable-depth-copy-to-prevent.html

2 голосов
/ 30 марта 2012

Можно клонировать объект, стереть идентификатор и сохранить его обратно, чтобы назначить новый идентификатор.

, поэтому

Person person = EmployeeDAO.get(empId);
Person newPersonCopy = person.createCopyWithNoId()
EmployeeDAO.add(newPersonCopy);

в этом случае createCopyWithNoId () создаст клон объекта и установит для поля Id значение null.когда вы сейчас добавляете новый клон, механизм гибернации увидит его как новый объект, сохранит его, а база данных назначит новый первичный ключ.

Обратите внимание, что я избегал вызова метода клон, потому что то, что выходит, неточный клон, когда мы манипулируем Id (устанавливая его в ноль);

Еще один способ - добавить конструктор, который принимает объект типа person и создает новый объект, но просто не устанавливает Idполе, оставляя его по умолчанию значение ноль.Снова вы продолжаете использовать DAO.

1 голос
/ 06 сентября 2018

Как я объяснил в этой статье , использование detach или глубокое клонирование, как предлагают другие, не являются подходящим способом, когда речь идет о клонировании сущности. Если вы попытаетесь сделать этот процесс полностью автоматическим, вы упустите момент, когда не все атрибуты заслуживают дублирования.

Поэтому вам лучше использовать конструктор копирования и точно контролировать, какие атрибуты необходимо клонировать.

Итак, если у вас есть Post сущность, подобная этой:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @OneToMany(
        mappedBy = "post",
        cascade = CascadeType.ALL, 
        orphanRemoval = true
    )
    private List<PostComment> comments = new ArrayList<>();

    @OneToOne(
        mappedBy = "post",
        cascade = CascadeType.ALL, 
        orphanRemoval = true, 
        fetch = FetchType.LAZY
    )
    private PostDetails details;

    @ManyToMany
    @JoinTable(
        name = "post_tag",
        joinColumns = @JoinColumn(
            name = "post_id"
        ),
        inverseJoinColumns = @JoinColumn(
            name = "tag_id"
        )
    )
    private Set<Tag> tags = new HashSet<>();

    //Getters and setters omitted for brevity

    public void addComment(
            PostComment comment) {
        comments.add(comment);
        comment.setPost(this);
    }

    public void addDetails(
            PostDetails details) {
        this.details = details;
        details.setPost(this);
    }

    public void removeDetails() {
        this.details.setPost(null);
        this.details = null;
    }
}

Нет смысла клонировать comments при дублировании Post и использовании его в качестве шаблона для нового:

Post post = entityManager.createQuery(
    "select p " +
    "from Post p " +
    "join fetch p.details " +
    "join fetch p.tags " +
    "where p.title = :title", Post.class)
.setParameter(
    "title", 
    "High-Performance Java Persistence, 1st edition"
)
.getSingleResult();

Post postClone = new Post(post);
postClone.setTitle(
    postClone.getTitle().replace("1st", "2nd")
);
entityManager.persist(postClone);

То, что вам нужно добавить к сущности Post, - это конструктор копирования:

/**
 * Needed by Hibernate when hydrating the entity 
 * from the JDBC ResultSet
 */
private Post() {}

public Post(Post post) {
    this.title = post.title;

    addDetails(
        new PostDetails(post.details)
    );

    tags.addAll(post.getTags());
}

Итак, конструктор копирования - лучший способ решить проблему клонирования / дублирования сущности.

0 голосов
/ 27 февраля 2019

1 - добавить зависимость commons-lang в файл pom.xml

<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

2- Импорт org.apache.commons.lang.SerializationUtils3- Используйте SerializationUtils.clone(oldObj)ех.Class1 newObj = (Class1) SerializationUtils.clone(oldObj);

см. Также java-deep-copy

0 голосов
/ 30 марта 2012

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

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