2009-07-09 26 views
5

Tengo un objeto de usuario que tiene una relación uno a muchos con tipos de cadenas. Creo que son mapeos simples. La tabla de tipos contiene el nombre de usuario asociado y los nombres de tipo de variable, con una clave principal 'id' que básicamente es un contador.Hibernar Guardar comportamiento extraño

<class name="Users" table="users"> 
    <id column="id" name="id" /> 
    ... 
    <set name="types" table="types" cascade="save-update"> 
     <key column="id" /> 
     <one-to-many class="Types" /> 
    </set> 
</class> 

<class name="Types" table="types"> 
    <id column="id" name="id" /> 
    <property column="user_id" name="user_id" type="integer" /> 
    <property column="type" name="type" type="string" /> 
</class> 

Este es el java utilicé para añadir a la base de datos:

User u = new User(); 
u.setId(user_id); 
... 
Collection<Types> t = new HashSet<Types>(); 
t.add(new Type(auto_incremented_id, user_id, type_name)); 
u.setTypes(t); 

getHibernateTemplate().saveOrUpdate(u); 

Cuando lo ejecuto, se da este error:

61468 [http-8080-3] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1062, SQLState: 23000 
61468 [http-8080-3] ERROR org.hibernate.util.JDBCExceptionReporter - Duplicate entry '6' for key 'PRIMARY' 
61468 [http-8080-3] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session 
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update 

Cuando compruebo el SQL, muestra:

Hibernate: insert into users (name, id) values (?, ?) 
Hibernate: insert into types (user_id, type, id) values (?, ?, ?) 
Hibernate: update types set id=? where id=? 
  • ¿Por qué Hibernate intenta actualizar la identificación de los tipos?

El error dice: Duplicar la entrada '6' para la clave 'PRIMARY', pero realmente no? Me aseguré de que los identificadores se incrementaran cada vez. Y los usuarios y tipos se agregan a la base de datos correctamente.

He registrado la información que entra, y los tipos agregados tienen un id de 7 y una identificación de usuario de 6. Podría ser que Hibernate tomara el user_id de 6 y tratara de actualizar los tipos y estableciera id = 6 donde id = 7? Por lo tanto, ¿el error duplicado de la clave primaria?

¿Pero por qué haría algo tan extraño? ¿Hay alguna manera de evitar que se actualice?

  • ¿Debo configurar el ID manualmente? Si no, ¿cómo debería agregar los tipos? Da otros errores cuando agrego un tipo de objeto que solo tiene una cadena de tipo y sin identificadores.

Gracias chicos. Ha estado reflexionando sobre ello durante días ...

Respuesta

2

Su mayor problema es la columna incorrecta en la asignación <key> - debe ser "user_id", no "id". Dicho eso, toda tu asignación me parece un poco extraña.

En primer lugar, si quieres identificadores de auto genera realmente debería dejar que Hibernate se encarga de eso especificando generador apropiado:

 
<id column="id" name="id"> 
    <generator class="native"/> 
</id> 

Leer Hibernate Documentation de generadores para las diferentes opciones disponibles.

En segundo lugar, si todo lo que necesita es un conjunto de tipos de cadenas, considere volver a la cartografía de ellas en una colección de elementos en lugar de uno-a-muchos relación:

 
<set name="types" table="types"> 
    <key column="user_id"/> 
    <element column="type" type="string"/> 
</set> 

De esa manera no se necesita clase o mapeo explícito de "Tipos" para él. Incluso si desea tener atributos adicionales en "Tipos", aún puede asignarlo como componente en lugar de como entidad.

Por último, si los "tipos" debe ser una entidad debido a algún requisito no se ha descrito, la relación entre los "Usuarios" y "tipos" es bidireccional y necesita ser asignada como tal:

 
<set name="types" table="types" inverse="true"> 
    <key column="user_id"/> 
    <one-to-many class="Types"/> 
</set> 

... 
in Types mapping: 
<many-to-one name="user" column="user_id" not-null="true"/> 

En este último caso, "Tipos" debería tener una propiedad de "usuario" de tipo "Usuarios". Here es un ejemplo detallado.

+0

pegado con colección de elementos! ¡Gracias! – April

0

La solución que funcionó para mí era salvar por separado las dos partes (sin añadir el tipo de usuario):

getHibernateTemplate().save(user); 
getHibernateTemplate().save(new Type(user.id, type_name)); 

Y con la < clase generador = "nativo" /> sólo en el tipo de identificación.

¿Una mala práctica?

Lo había mapeado como una colección de elementos, pero de alguna manera erróneamente se agregaba el user_id a la columna de id de tipos, lo que a veces causaba errores duplicados; ya que los tipos id es la única columna de clave principal. ¡Extraño! Recuerdo que había algún otro error en la columna, pero me olvidé de ello, porque de inmediato volví a la relación uno a muchos. No se pudo captar las extrañas funcionamiento de Hibernate ...

voy a tratar la solución bidireccional en algún momento ... Muchas gracias por toda la ayuda :)

+1

Me temo que te estás perdiendo el objetivo por completo. Deberías dejar que Hibernate te haga la vida más fácil, no luchar con ello en cada paso del camino, y tener asignaciones correctas sería muy útil para lograrlo. El escenario que describió anteriormente es muy básico; hay muchos ejemplos disponibles (publiqué enlaces en mi respuesta). Realmente necesita leer la documentación, hacer que esto funcione y comprender cómo funciona; de lo contrario, será mucho más difícil en el camino. – ChssPly76

+0

Sí, sé que es muy básico, así que estoy confundido por qué todavía se rompe. Al usar esta solución, hibernate intenta buscar tipos haciendo coincidir el tipo id con user_id, lo cual es completamente extraño. Así que hice la colección de elementos mencionados anteriormente, y ahora tengo un error de conversión de clase. ¡Hacer las asignaciones para Hibernate hace la vida tan difícil! Cada vez que hay una asignación, no hacen un seguimiento de cómo se puede acceder o recuperar los objetos. Tienes que buscar y cavar en otro lugar. – April