it-swarm.com.de

Hibernate-Objektwerte in neues Objekt mit neuer generierter ID kopieren

Ich verwende eine relationale Datenbank mit nur einer Spalte mit ein paar geschachtelten Tabellen. Ich muss meinem Projekt eine einfache Archivierung hinzufügen. Die Archivierung findet nur statt, wenn die Anwendung einen bestimmten Status erreicht. Ich habe also erwartet, dass ich mein vorhandenes Ruhezustandobjekt in eine neue Instanz kopiert, in der die neue Instanz mit einer neuen ID gespeichert wird, während das vorhandene Objekt intakt bleibt. Ich kann anscheinend nicht herausfinden, wie ich das vorhandene Objekt in eine neue Instanz kopieren kann, ohne jedes einzelne neue Instanzfeld manuell festlegen zu müssen. Kennt jemand eine einfache Möglichkeit, dies zu tun?

22
Code Junkie

Ich arbeite auch mit Hibernate und habe die gleiche Anforderung wie Sie. Was ich folgte, war die Implementierung von Cloneable. Nachfolgend finden Sie ein Codebeispiel, wie es gemacht wird.

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

Oder Sie gehen zu einer reflexionsbasierten Lösung, die ich jedoch nicht empfehlen kann. Überprüfen Sie diese Website für weitere Details.

6
Chan

Rufen Sie einfach das Objekt ab, trennen Sie es, setzen Sie die ID auf null und behalten Sie es bei. 

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

Wenn Ihr Objekt oneToMany-Beziehungen hat, müssen Sie den Vorgang für alle untergeordneten Objekte wiederholen, müssen jedoch Ihre übergeordnete Objekt-ID (die nach dem Aufruf persist generiert wurde) anstelle von null festlegen.

Natürlich müssen Sie jeden CASCADE persist in Ihren OneToMany-Beziehungen entfernen, da andernfalls Ihre Persistenz Duplikate aller untergeordneten Elemente in DB- oder fk-Integritätsfehlern erstellt.

34
Gab

Schauen Sie sich den folgenden Link an. einer der leistungsstärksten Klonmechanismen, der mit Hibernate auf effektivste Weise genutzt werden kann

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

Sie können das Objekt klonen und die ID löschen und erneut speichern, sodass eine neue ID zugewiesen wird.

so

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

in diesem Fall würde das createCopyWithNoId () einen Klon des Objekts erstellen und das Id-Feld auf null setzen. Wenn Sie nun den neuen Klon hinzufügen, wird das Hibernate-Modul als neues Objekt angezeigt, und der Datenbank wird ein neuer Primärschlüssel zugewiesen.

Bitte beachten Sie, dass ich den Aufruf der Methode clone vermieden habe, weil das, was herauskommt, kein exakter Klon ist, da wir die Id manipulieren (null setzen).

Eine andere Möglichkeit wäre, einen Konstruktor hinzuzufügen, der ein Objekt des Typs person aufgenommen und ein neues Objekt erstellt hat, das Feld Id jedoch nicht auf den Standardwert null gesetzt hat. Wiederum bleiben Sie mit der DAO beharrlich.

2
krystan honour

Wie ich in diesem Artikel erläutert habe, ist die Verwendung von detach oder Deep Cloning, wie von anderen vorgeschlagen, nicht der richtige Weg, wenn es um das Klonen einer Entität geht. Wenn Sie versuchen, diesen Prozess vollständig automatisch zu gestalten, werden Sie den Punkt verpassen, dass nicht alle Attribute es wert sind, dupliziert zu werden.

Daher ist es besser, einen Kopierkonstruktor zu verwenden und genau zu steuern, welche Attribute geklont werden müssen.

Wenn Sie also eine Post-Entität wie diese haben:

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

Es macht keinen Sinn, die comments zu duplizieren, wenn eine Post dupliziert und als Vorlage für eine neue verwendet wird:

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

Was Sie zur Post-Entität hinzufügen müssen, ist ein Kopierkonstruktor:

/**
 * 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());
}

Daher ist der Kopierkonstruktor der beste Weg, um das Entitätsklon-/Duplikationsproblem zu lösen.

1
Vlad Mihalcea

Sie können entweder klonen, wenn das Objekt klonbar ist, oder Sie können eine Methode/einen Konstruktor für das Objekt, das Sie kopieren möchten, definieren, indem Sie einen Parameter von sich selbst nehmen und alles, was Sie benötigen, in eine neue Instanz kopieren und Ihnen zurückgeben.

0
fmucar

1- Fügen Sie der Datei pom.xml die Abhängigkeit commons-lang hinzu

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

2- Importieren Sie org.Apache.commons.lang.SerializationUtils

3- Verwenden Sie SerializationUtils.clone(oldObj)

Ex. Class1 newObj = (Class1) SerializationUtils.clone(oldObj);

siehe auch Java-Deep-Copy

0
Waleed Emad