2009-04-28 12 views
2

J'ai une simple hiérarchie de classes que j'essaie d'utiliser avec Hibernate/JPA.Séparation d'une entité Hibernate entre 2 tables

Fondamentalement, ce que je veux, c'est que les données de mouvement soient dans leur propre table avec un FK à l'id entier de la table de véhicule principal dans la base de données.

Est-ce que je fais quelque chose de mal? Comment puis-je accomplir quelque chose de similaire? Je suis sûr que je suis la spécification JPA. (EJB3 En action dit cela devrait fonctionner: EJB3 In Action: @SecondaryTable

est ici une partie de l'exception que je reçois:

SEVERE: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session) 
org.hibernate.AssertionFailure: Table MOVEMENT_DATA not found 
    at org.hibernate.persister.entity.JoinedSubclassEntityPersister.getTableId(JoinedSubclassEntityPersister.java:480) 
    at org.hibernate.persister.entity.JoinedSubclassEntityPersister.<init>(JoinedSubclassEntityPersister.java:259) 
    at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:87) 
    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:261) 
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1327) 

Voici quelques-unes des informations de log d'Hibernate qui concerne le véhicule ... Il dirait qu'il reconnaît tout va bien .. Ensuite, il jette l'exception pour une raison quelconque.

INFO: Binding entity from annotated class: com.dataobject.Vehicle 
FINE: Import with entity name Vehicle 
INFO: Bind entity com.dataobject.Vehicle on table VEHICLE 
INFO: Adding secondary table to entity com.dataobject.Vehicle -> MOVEMENT_DATA 
FINE: Processing com.dataobject.Vehicle property annotation 
FINE: Processing annotations of com.dataobject.Vehicle.id 
FINE: Binding column id. Unique false. Nullable false. 
FINE: id is an id 
FINE: building SimpleValue for id 
FINE: Building property id 
FINEST: Cascading id with null 
FINE: Bind @Id on id 
FINE: Processing annotations of com.dataobject.Vehicle.color 
FINE: Binding column COLOR. Unique false. Nullable true. 
FINE: binding property color with lazy=false 
FINE: building SimpleValue for color 
FINE: Building property color 
FINEST: Cascading color with null 
FINE: Processing annotations of com.dataobject.Vehicle.movementData 
FINE: Binding column movementData. Unique false. Nullable true. 
FINE: Binding component with path: com.dataobject.Vehicle.movementData 
FINE: Processing com.dataobject.MovementData property annotation 
FINE: Processing annotations of com.dataobject.MovementData.latitude 
FINE: Column(s) overridden for property latitude 
FINE: Binding column LATITUDE. Unique false. Nullable true. 
FINE: binding property latitude with lazy=false 
FINE: building SimpleValue for latitude 
FINE: Building property latitude 
FINEST: Cascading latitude with null 
FINE: Processing annotations of com.dataobject.MovementData.longitude 
FINE: Column(s) overridden for property longitude 
FINE: Binding column LONGITUDE. Unique false. Nullable true. 
FINE: binding property longitude with lazy=false 
FINE: building SimpleValue for longitude 
FINE: Building property longitude 
FINEST: Cascading longitude with null 
FINE: Processing annotations of com.dataobject.MovementData.speed 
FINE: Column(s) overridden for property speed 
FINE: Binding column SPEED. Unique false. Nullable true. 
FINE: binding property speed with lazy=false 
FINE: building SimpleValue for speed 
FINE: Building property speed 
FINEST: Cascading speed with null 
FINE: Processing annotations of com.dataobject.MovementData.timeOfPosition 
FINE: Column(s) overridden for property timeOfPosition 
FINE: Binding column TIME_OF_POSITION. Unique false. Nullable true. 
FINE: binding property timeOfPosition with lazy=false 
FINE: building SimpleValue for timeOfPosition 
FINE: Building property timeOfPosition 
FINEST: Cascading timeOfPosition with null 
FINE: Building property movementData 
FINEST: Cascading movementData with null 
FINE: Processing annotations of com.dataobject.Vehicle.numWheels 
FINE: Binding column NUM_WHEELS. Unique false. Nullable true. 
FINE: binding property numWheels with lazy=false 
FINE: building SimpleValue for numWheels 
FINE: Building property numWheels 
FINEST: Cascading numWheels with null 
INFO: Binding entity from annotated class: com.dataobject.Car 
FINE: Binding column id. Unique false. Nullable false. 
FINE: Subclass joined column(s) created 
FINE: Import with entity name Car 
INFO: Bind entity com.dataobject.Car on table CAR 
FINE: Processing com.dataobject.Car property annotation 
FINE: Processing annotations of com.dataobject.Car.make 
FINE: Binding column MAKE. Unique false. Nullable true. 
FINE: binding property make with lazy=false 
FINE: building SimpleValue for make 
FINE: Building property make 

véhicule est la classe parente

/** 
* Entity implementation class for Entity: Vehicle 
* 
*/ 
@Entity 
@Table(name="VEHICLE") 
@Inheritance(strategy=InheritanceType.JOINED) 
@SecondaryTable(name="MOVEMENT_DATA", 
      pkJoinColumns = { 
       @PrimaryKeyJoinColumn(name = "ID") 
      } 
) 
public class Vehicle implements Serializable { 


    private int numWheels; 
    private String color; 
    private int id; 
    private MovementData movementData; 
    private static final long serialVersionUID = 1L; 


    public Vehicle() { 
     super(); 
    } 

    @Embedded 
    @AttributeOverrides({ 
    @AttributeOverride(
     name = "speed", 
     column = @Column(name = "SPEED", 
         table = "MOVEMENT_DATA") 
    ), 
    @AttributeOverride(
     name = "timeOfPosition", 
     column = @Column(name = "TIME_OF_POSITION", 
         table = "MOVEMENT_DATA") 
    ), 
    @AttributeOverride(
      name = "longitude", 
      column = @Column(name = "LONGITUDE", 
          table = "MOVEMENT_DATA") 
     ), 
    @AttributeOverride(
      name = "latitude", 
      column = @Column(name = "LATITUDE", 
          table = "MOVEMENT_DATA") 
     ) 
}) 
    public MovementData getMovementData() { 
     return movementData; 
    } 
    public void setMovementData(MovementData movementData) { 
     this.movementData = movementData; 
    } 

    @Column(name="NUM_WHEELS") 
    public int getNumWheels() { 
     return this.numWheels; 
    } 

    public void setNumWheels(int numWheels) { 
     this.numWheels = numWheels; 
    } 
    @Column(name="COLOR") 
    public String getColor() { 
     return this.color; 
    } 

    public void setColor(String color) { 
     this.color = color; 
    } 
    @Id  
    public int getId() { 
     return this.id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

} 

étend voiture véhicule

/** 
* Entity implementation class for Entity: Car 
*/ 
@Entity 
@Table(name="CAR") 
public class Car extends Vehicle implements Serializable { 


    private String make; 
    private static final long serialVersionUID = 1L; 

    public Car() { 
     super(); 
    } 
    /** 
    * @return 
    */ 
    @Column(name="MAKE") 
    public String getMake() { 
     return this.make; 
    } 

    /** 
    * @param make 
    */ 
    public void setMake(String make) { 
     this.make = make; 
    } 

} 

MovementData est intégré dans des véhicules

@Embeddable 
public class MovementData implements Serializable { 


    private double speed; 
    private Date timeOfPosition; 
    private double latitude; 
    private double longitude; 
    private static final long serialVersionUID = 1L; 

    public MovementData() { 
     super(); 
    } 



    /** 
    * @return 
    */ 
    @Column(name="SPEED") 
    public double getSpeed() { 
     return this.speed; 
    } 

    /** 
    * @param speed 
    */ 
    public void setSpeed(double speed) { 
     this.speed = speed; 
    } 
    /** 
    * @return 
    */ 
    @Column(name="TIME_OF_POSITION") 
    public Date getTimeOfPosition() { 
     return this.timeOfPosition; 
    } 

    /** 
    * @param timeOfPosition 
    */ 
    public void setTimeOfPosition(Date timeOfPosition) { 
     this.timeOfPosition = timeOfPosition; 
    } 

    /** 
    * @return 
    */ 
    @Column(name="LONGITUDE") 
    public double getLongitude() { 
     return this.longitude; 
    } 

    /** 
    * @param longitude 
    */ 
    public void setLongitude(double longitude) { 
     this.longitude = longitude; 
    } 
    /** 
    * @return 
    */ 
    @Column(name="LATITUDE") 
    public double getLatitude() { 
     return this.latitude; 
    } 

    /** 
    * @param latitude 
    */ 
    public void setLatitude(double latitude) { 
     this.latitude = latitude; 
    } 

} 

Unité Persistance:

<properties> 
     <!-- The database dialect to use --> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> 
     <!-- drop and create tables at deployment --> 
     <property name="hibernate.hbm2ddl.auto" value="create-drop" /> 
     <!-- Hibernate Query Language (HQL) parser. --> 
     <!-- property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" /--> 
     <!-- property name="hibernate.cache.provider_class" value="org.hibernate.cache.JbossCacheProvider" /--> 
     <property name ="hibernate.show_sql" value="false" /> 
     <property name ="hibernate.format_sql" value="false" /> 
     <property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" /> 
    </properties> 

Répondre

1

Au cours du développement il est souvent pratique d'avoir cette propriété a permis:

cfg.setProperty(Environment.HBM2DDL_AUTO, "update"); 

où cfg est mon AnnotationConfiguration.

Votre problème sera probablement résolu en activant cette propriété.

+0

je create-drop set (voir mon persistence.xml ci-dessus). Je l'ai juste essayé avec la mise à jour à la place, et cela ne fonctionne toujours pas avec la même erreur. – systemoutprintln

+1

REMARQUE pour toute personne ayant ce problème: Réponse a été sélectionnée automatiquement ... Cela ne fonctionne pas. – systemoutprintln

0

De l'exception que vous avez publiée, il apparaît que la table n'a pas encore été créée dans votre base de données ("Table MOVEMENT_DATA non trouvée"). Si vous n'avez pas demandé à Hibernate/JPA de modifier votre schéma, vous devez ajouter manuellement la table avant d'exécuter votre code (je crois que c'est CREATE-UPDATE pour indiquer à hibernate d'effectuer les modifications).

+0

J'ai déjà dans mon persistence.xml – systemoutprintln

0

Définition de la classe intégrable ne devrait pas table de base de données de référence:

@Embeddable 
public class MovementData implements Serializable { 


    private double speed; 
    private Date timeOfPosition; 
    private double latitude; 
    private double longitude; 
    private static final long serialVersionUID = 1L; 

    public MovementData() { 
     super(); 
    } 

    @Column(name="SPEED") 
    public double getSpeed() { 
     return this.speed; 
    } 

    ... 

    @Column(name="TIME_OF_POSITION") 
    public Date getTimeOfPosition() { 
     return this.timeOfPosition; 
    } 

    ... 

    @Column(name="LONGITUDE") 
    public double getLongitude() { 
     return this.longitude; 
    } 

    ... 

    @Column(name="LATITUDE") 
    public double getLatitude() { 
     return this.latitude; 
    } 

    ... 
} 

alors entité véhicule devrait définir table secondaire pour la structure intégrée y compris colonne de jointure:

@Entity 
@Table(name="VEHICLE") 
@Inheritance(strategy=InheritanceType.JOINED) 
@SecondaryTable(name="MOVEMENT_DATA", 
       pkJoinColumns = { 
        @PrimaryKeyJoinColumn(name = "ID") 
       } 
) 
public class Vehicle implements Serializable { 


    private int numWheels; 
    private String color; 
    private int id; 
    private MovementData movementData; 
    private static final long serialVersionUID = 1L; 


    public Vehicle() { 
     super(); 
    } 

    @Embedded 
    @AttributeOverrides({ 
     @AttributeOverride(
      name = "speed", 
      column = @Column(name = "SPEED", 
          table = "MOVEMENT_DATA") 
     ), 
     @AttributeOverride(
      name = "timeOfPosition", 
      column = @Column(name = "TIME_OF_POSITION", 
          table = "MOVEMENT_DATA") 
     ), 

     ... // override the rest of the attributes 

    }) 
    public MovementData getMovementData() { 
     return movementData; 
    } 

    ... 

    @Id  
    public int getId() { 
     return this.id; 
    } 

    ... 
} 

J'espère que cela travailler pour vous.

+0

Merci pour l'aide ... Toujours obtenir la même erreur cependant. Je suis à ma fin d'esprit! – systemoutprintln

+1

Quand je rencontre des problèmes de ce genre, j'essaie de simplifier le terrain de jeu pour le rendre aussi transparent que possible. Dans ce cas, je supprimerais la configuration de l'héritage de l'entité Véhicule - de cette façon, vous traiterez un problème à la fois (espérons-le). Après avoir résolu le problème de l'objet incorporable dans une table secondaire, retournez l'héritage et voyez comment ils fonctionnent ensemble. – topchef

1

Je voudrais essayer de résoudre ce problème pour trouver le problème. Essayez de créer des données de mouvement dans une entité au lieu d'une classe intégrable. Assurez-vous qu'il peut se tenir tout seul et ensuite le remettre à embeddable.

Bien que ce ne est pas vraiment la relation que vous voulez, vous pourriez essayer de faire MovementData le parent racine et ont hériter des véhicules hors de MovementData. De cette façon, vous ne travaillerez qu'avec

@Inheritance(strategy=InheritanceType.JOINED) 

au lieu de l'héritage plus table secondaire. Cela simplifierait la relation tout en incluant toutes les tables.

+0

Ah .. Je pense que vous avez raison .. Il peut être un problème avec le mélange de @SecondaryTable avec la stratégie d'héritage jointe, puisque, d'un point de vue DB, ils se ressemblent. Ce n'est pas vraiment une solution idéale, car je veux que mes entités Java ressemblent à ci-dessus. – systemoutprintln

+0

Donc, vous pouvez également en faire non pas une table secondaire, mais juste une relation OneToOne entre Vehicle et MovementData. Avec les cascades de droite, il se comporterait de la même manière. – ccclark

-1

Connectez-vous à votre base de données en utilisant votre client approprié db (navigateur Query, MS SQL Managment studio, etc) afin de vérifier si oui ou non les tableaux font, en fait, existent.

Vous pouvez également insérer un point d'arrêt dans votre code afin que vous puissiez voir exactement ce que la base de données ressemble au moment avant qu'il ne soit lancer cette erreur.

Essayez de régler la valeur hibernate.hbm2ddl.auto à « créer » comme ci-dessous, et aussi changer le réglage de sorte qu'il imprime SQL afin que vous puissiez voir ce qu'il tente:

<props> 
    <!-- some possible values: create, create-drop, update --> 
    <prop key="hibernate.hbm2ddl.auto">update</prop> 
    <prop key="hibernate.show_sql">true</prop> 
    .... 
<props> 

Laissez-moi savoir ce que vous voyez dans votre db.

+0

Il finit par ne rien créer dans la base de données réelle quand je le mets à créer. Il jette cette exception avant ce point. J'ai ajouté un peu plus de l'information de notation à mon poste ci-dessus. – systemoutprintln

+0

Pourquoi ne pas essayer d'ajouter le nom de colonne Id au champ Id du véhicule, comme ceci: @Id @Column (name = "ID") public int getId() { retour this.id; } – Cuga

1

je suppose que son chemin trop tard pour cela, mais je suis tombé sur la question lors de la recherche d'autre chose.

Le problème est qu'une classe intégrable ne correspond pas à une table - un objet embarquable n'a pas d'identité dans la base de données.

C'est pourquoi aucune table MovementData n'est générée.

Je pense que vous avez confondu la signification de Embedded. Comme mentionné par un intervenant précédent, Vehicle et MovementData doivent être dans une relation OneToOne, et les annotations incorporées doivent être supprimées. Vous pourriez avoir besoin d'une règle d'élimination en cascade pour vous assurer que si un véhicule est retiré, les données de mouvement le sont aussi.