2011-12-14 19 views
14

He encontrado severalquestionsabout esto, pero ninguno con una explicación completa del problema, y ​​cómo depurarlo - las respuestas son todas anecdóticas.Cómo depurar "¿Encontré dos representaciones de la misma colección"?

El problema es que en una prueba de APP Juego 1.2.4, estoy recibiendo esta excepción cuando I save() un modelo:

org.hibernate.HibernateException: Encontrado dos representaciones de la misma colección : modelos .Position.projects

me gustaría saber:

  1. ¿existe una documentación de este problema, en general, de la ONU relacionado con Play? El problema está en hibernación, sin embargo, muchos de los resultados de Google sobre esto están dentro de las aplicaciones Play.
  2. ¿Cuáles son algunas de las mejores prácticas básicas para evitar este problema?
  3. ¿Es causado por Play? O algo que estoy haciendo mal?
  4. ¿Cómo resolver en mi caso específico?

Here is a reproduction of the problem on github. Tengo cuatro entidades:

@Entity 
public class Person extends Model { 
    public String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    public List<Position> positions; 
} 


@Entity 
public class Position extends Model { 
    public Position(){} 
    public Position(Company companies) { 
     this.companies = companies; 
     this.projects = new ArrayList<Project>(); 
    } 

    @OneToOne 
    public Company companies; 

    @ManyToOne 
    public Person person; 

    @OneToMany 
    public List<Project> projects; 
} 

@Entity 
public class Company extends Model { 
    public String name; 
} 

@Entity 
public class Project extends Model { 
    public Project(){} 
    public Project(String field, String status){ 
     this.theField = field; 
     this.status = status; 
    } 

    @ManyToOne 
    public Position position; 

    public String theField; 
    public String status; 
} 

Y mi código de persistencia:

Company facebook = new Company(); 
facebook.name = "Facebook"; 
facebook.save(); 
Company twitter = new Company(); 
twitter.name = "Twitter"; 
twitter.save(); 

Person joe = new Person(); 
joe.name = "Joe"; 
joe.save(); 

joe.positions = new ArrayList<Position>(); 

Position joeAtFacebook = new Position(facebook); 
joeAtFacebook.projects.add(new Project("Stream", "Architect")); 
joeAtFacebook.projects.add(new Project("Messages", "Lead QA")); 
joe.positions.add(joeAtFacebook); 

Position joeAtTwitter = new Position(twitter); 
joeAtTwitter.projects.add(new Project("Steal stuff from Facebook", "CEO")); 
joe.positions.add(joeAtTwitter); 
joe.save(); 

Por cierto, he intentado añadir el Play associations module como una persona sugirió, y does't parece ayudar.

veo que, efectivamente, que las tablas que se crean son duplicado en un sentido:

tengo tanto una mesa person_position y una position table, donde ambos contienen campos similares: person_position contiene una Person_id y positions_id, mientras que la mesa position contiene id (es decir, identificación de posición), person_id y companies_id. Así que entiendo que la definición de mi modelo crea algún tipo de redundancia involuntaria, pero realmente no entiendo cómo resolverlo.

Pensé que esto podría estar relacionado con las asignaciones bidireccionales, pero aquí está un branch where the model is uni-directional (eliminé algunas referencias) y el problema persiste.

+0

my guess - cascading problem. agrega una Posición, y la posición agrega dos proyectos, entonces joe.save() puede causar que se agregue la posición dos veces. Juega con las opciones de Cascade e informa de nuevo :) –

+0

@KenEgozi - ¿Las opciones en cascada afectan cómo se generan mis tablas? Debido a que tengo una duplicación en la estructura de la tabla en sí ... (Puse los detalles en la pregunta) – ripper234

+0

@KenEgozi - resuelto al actualizar la versión de hibernación - ver mi respuesta. Gracias. – ripper234

Respuesta

7

Trate

 @OneToMany(mappedBy="position") 
        public List<Project> projects; 
+0

Eso fue parte de la solución, gracias. – ripper234

+1

Además, si está utilizando ** persist (entidad) ** y todas sus @ OneToMany ya tienen una propiedad "mappedBy", podría intentar usar ** merge (entity) ** en su lugar. – izilotti

9

Por lo que yo he sido capaz de decir, el error es causado por cualquier combinación de:

  • carecer/mappedBy falta de parámetros en @OneToMany anotaciones. Este parámetro debe recibir el nombre del campo en el modelo de destino que hace referencia a este modelo.
  • hibernación antigua - Play 1.2.4 incluye hibernación 3.6.1 ... la actualización a 3.6.8 parece resolver otro problema similar (solo agregue lo siguiente a las dependencias).yml, y el juego deps)

- org.hibernate -> hibernate-core 3.6.8.Final:

force: true

Para mí, los pasos anteriores resuelven el problema.

De hecho, es un error en la hibernación, ya que se produce cuando persisten objetos, mientras que en realidad implica un problema de "tiempo de diseño" que se debe detectar al crear el esquema.

pasos que he utilizado para depurar:

  • escribió una prueba que reproduce el problema
  • Agregado el associations module - No estoy seguro de si se resuelve una parte del problema, o agravante.
  • Depurado a través del código de hibernación, y me di cuenta que esto probablemente indica un problema de hibernación, no un error de usuario/configuración.
  • Noté que hibernate tiene bastantes versiones de corrección de errores después de 3.6.1, y decidí probar suerte y actualizar.
  • También es importante que la limpieza de la carpeta tmp no se vea afectada. Reproduzca en caché los archivos compilados allí y, después de un cambio importante como la actualización de la versión de hibernación, podría valer la pena limpiarlo.
+0

No entiendo por qué indicó las anotaciones de ManyToOne en absoluto ... parece extraño que en una definición para una entidad única esté especificando que muchas de estas entidades estarán relacionadas con una sola entidad. (Entiendo al revés.) pero creo que debe ser implícitamente entendido por el marco. (No tengo mucha experiencia hibrnate, lo admito) –

+0

@ItayLevin - No estoy seguro de por qué es exactamente necesario, pero creo que está ahí por una buena razón. Leeré el tutorial de Hibernate y veré si voy a ser mártir después de eso. – ripper234

1

En primer lugar creo que se olvida de una línea de uno antes de la última:

joe.positions.add(joeAtTwitter); 

Segundo: creo que no se debe hacer

joe.positions = new ArrayList<Position>(); 

vez cambiar Person a:

@Entity 
public class Person extends Model { 
    public String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    public List<Position> positions = new ArrayList<Position>(); 
} 

Lo hará resuelva su problema, además de que es una buena práctica, usar la colección vacía en lugar del valor null (ver Java efectivo) en general y específicamente para trabajar con objetos administrados de Hibernate. Lea el primer párrafo here para obtener una explicación de por qué es mejor inicializar con colecciones vacías.

Ahora lo que creo que pasó es: cuando se llama joe.save() que ha hecho el objeto gestionado (por Hibernate), entonces usted ha sobrescrito una propiedad con una nueva colección, no puedo entender por qué el error que tienes es de aproximadamente model.Position.projects, pero creo que ese es el caso.

+0

Gracias por la ayuda. Tal vez no me haya aclarado en mi respuesta anterior, pero al especificar la propiedad mappedBy y actualizar desde hibernación 3.6.1 a 3.6.8 resolví el problema por mí. De todos modos, arreglé mi pregunta de acuerdo con su primera sugerencia. – ripper234

Cuestiones relacionadas