Pregunta

Tengo un proyecto APP conectado a una base de datos MySQL donde mi objeto de entidad se asigna a una mesa con una restricción en 2 columnas. Es decir:

@Entity
@Table(name = "my_entity")
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "myField1")
    private String myField1;
    @Basic(optional = false)
    @Column(name = "myField2")
    private int myField2;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "myEntity")
    private Set<OtherEntity> otherEntitySet;
}

En la base de datos, la tabla my_entity tiene una restricción única en (myField1, myField2). La cuestión es que si quito una entidad existente con EntityManager.remove (entidad) y luego añadir una nueva con EntityManager.persist (entidad), la base de datos genera un error acerca de una fila duplicada.

Por ejemplo:

entityManager.getTransaction().begin();

MyEntity entity1 = new MyEntity();
entity1.setMyField1("Foo");
entity1.setMyField2(500);
entityManager.persist(entity1);

entityManager.getTransaction().commit();
entityManager.getTransaction().begin();

entityManager.remove(entity1);

MyEntity entity2 = new MyEntity();
entity2.setMyField1("Foo");
entity2.setMyField2(500); 
entityManager.persist(entity2);

entityManager.getTransaction().commit();

Esto me da una MySQLIntegrityConstraintViolationException quejándose de que esta es una entrada duplicada. Me imagino que es porque se trata de añadir la nueva entrada antes de retirar el antiguo. ¿Hay alguna manera de mantener ese orden? O, ¿hay una manera de utilizar la APP para evitar esta situación? No es exactamente un caso de uso común, pero estoy preocupado por un usuario que intenta eliminar una entidad para deshacerse de todos los datos asociados y empezar de nuevo, y luego recrea los campos más fácil, a continuación, encontrando que los datos nunca fue removido.

El código hash y es igual a implementaciones son las siguientes:

public int hashCode() {
    int hash = 0;
    hash += (getMyField1().hashCode() + getMyField2());
    return hash;
}

public boolean equals(Object object) {
    if (!(object instanceof MyEntity)) {
        return false;
    }
    MyEntity other = (MyEntity) other;
    return (getMyField2() == other.getMyField2()) &&
        (getMyField1().equals(other.getMyField1()));
}
¿Fue útil?

Solución

No creo que haya ninguna forma estándar para especificar ordenamiento operativo en JPA, por lo que no hay garantía de que orden se ejecutan las instrucciones. Lo ideal sería que la aplicación APP sería lo suficientemente inteligente como para detectar esta situación y llevar a cabo la eliminación antes de la inserción, pero que es un área que con frecuencia fallan en. Por otra parte, si su base de datos compatible restricción diferida de control (por ejemplo, Oracle MySQL hace pero no lo hace ), la base de datos podría manejar esta esperando hasta que cometió el momento de dar la única excepción restricción de violación.

Así que una solución es realizar simplemente un extra de confirmación después de su llamada para eliminar (Entity1). Otra posibilidad sería que, antes de crear entity2, a primera comprobación para ver si existe en la base de datos, y si es así, sólo tiene que utilizar esa. Ambas opciones pueden ser algo engorroso y no ser adecuado para todos los flujos de trabajo. Es posible que desee profundizar en la documentación de la actual implementación de JPA para ver si ofrecen extensiones que podría ayudar.

Otros consejos

Yo tenía el mismo problema que involucra una UC y las inserciones / deleciones ocurren en el orden equivocado. Tuve que crear una clave compuesta por mi entidad que coincidía con las columnas de la UC. Después de eso, las deleciones e inserciones se produjeron en el orden correcto. Ver este post, y el comentario acerca de la adición de un @EmbeddedId:

https://forum.hibernate.org/viewtopic.php?p=2382504

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top