La guía paso a paso o código que encontrarás en este post es la solución más eficiente y efectiva que hallamos a esta inquietud o problema.
Simplemente recupere el objeto, sepárelo, establezca la identificación en null y persistirlo.
MyEntity clone = entityManager.find(MyEntity.class, ID);
entityManager.detach(clone);
clone.setId(null);
entityManager.persist(clone);
Si su objeto tiene relaciones oneToMany, tendrá que repetir la operación para todos los hijos pero configurando su ID de objeto principal (generado después del persist
llamada) en lugar de null.
Por supuesto, tendrá que eliminar cualquier CASCADE persist
en sus relaciones OneToMany porque, de lo contrario, su persistencia creará duplicados de todos los niños en fallas de restricción DB o fk.
También estoy trabajando con Hibernate y obtuve el mismo requisito que usted. Lo que seguí fue implementar Cloneable
. A continuación se muestra un ejemplo de código de cómo hacerlo.
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;
O podría ir a una solución basada en la reflexión, pero no lo recomendaré. Consulte este sitio web para obtener más detalles.
Utilizando detach
o la clonación profunda, como sugieren otros, no es el camino a seguir cuando se trata de clonar una entidad. Si intenta hacer que este proceso sea completamente automático, se perderá el punto de que no todos attributes vale la pena duplicar.
Por lo tanto, es mejor usar un constructor de copias y controlar exactamente lo que attributes necesita ser clonado.
Entonces, si tienes un Post
entidad como esta:
@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 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 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;
No tiene sentido clonar el comments
al duplicar un Post
y usándolo como plantilla para uno nuevo:
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);
Lo que necesitas agregar a la Post
entidad es un constructor de copia:
/**
* 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());
Por lo tanto, el constructor de copias es la mejor manera de abordar el problema de duplicación/clonación de entidades.
Sección de Reseñas y Valoraciones
Recuerda algo, que te concedemos explicar tu experiencia .