2 Stimmen

Aufteilung einer Hibernate-Entität auf 2 Tabellen

Ich habe eine einfache Klassenhierarchie, die ich versuche, mit Hibernate/JPA zu arbeiten.

Grundsätzlich, was ich will, ist für die MovementData in eine eigene Tabelle mit einem FK auf die Integer-ID der Hauptfahrzeug-Tabelle in der Datenbank zu sein.

Mache ich etwas falsch? Wie kann ich sonst etwas Ähnliches erreichen? Ich bin mir ziemlich sicher, dass ich die JPA-Spezifikation befolge. (EJB3 In Action sagt, dass dies funktionieren sollte: EJB3 in Aktion: @SekundärTabelle

Hier ist ein Teil der Ausnahme, die ich erhalte:

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)

Hier sind einige der Protokollierungsinformationen von Hibernate, die sich auf das Fahrzeug beziehen... Es sieht so aus, als ob alles gut erkannt wird... Dann löst es aus irgendeinem Grund eine Ausnahme aus.

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

Fahrzeug ist die übergeordnete Klasse

/**
 * 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;
    }

}

Auto erweitert Fahrzeug

/**
 * 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 ist in das Fahrzeug eingebettet

@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;
    }   

}

Persistenz-Einheit:

    <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>

1voto

Schildmeijer Punkte 20362

Während der Entwicklung ist es oft praktisch, diese Eigenschaft aktiviert zu haben:

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

wobei cfg meine AnnotationConfiguration ist.

Ihr Problem wird höchstwahrscheinlich durch die Aktivierung dieser Eigenschaft gelöst.

1voto

ccclark Punkte 209

Ich würde versuchen, die Sache aufzuschlüsseln, um das Problem zu finden. Versuchen Sie, Bewegungsdaten in eine Entität anstelle einer einbettbaren Klasse zu machen. Stellen Sie sicher, dass es auf seine eigene stehen kann und dann ändern Sie es zurück zu embeddable.

Obwohl es nicht wirklich die Beziehung, die Sie wollen, könnten Sie versuchen, machen MovementData die Root-Eltern und haben Fahrzeug erben von MovementData. Auf diese Weise würden Sie nur arbeiten mit

@Inheritance(strategy=InheritanceType.JOINED)

anstelle von Vererbung plus secondaryTable. Das würde die Beziehung vereinfachen, aber immer noch alle Tabellen einschließen.

1voto

Dick Chesterwood Punkte 2494

Ich schätze, es ist viel zu spät dafür, aber ich bin auf diese Frage gestoßen, als ich nach etwas anderem gesucht habe.

Das Problem ist, dass eine Embeddable-Klasse nicht auf eine Tabelle abgebildet werden kann - ein Embeddable-Objekt hat keine Identität in der Datenbank.

Aus diesem Grund wird keine MovementData-Tabelle erstellt.

Ich glaube, Sie haben die Bedeutung von "eingebettet" verwechselt. Wie bereits von einem früheren Kommentator erwähnt, sollten Fahrzeug und MovementData in einer OneToOne-Beziehung stehen, und die Embedded-Anmerkungen sollten entfernt werden. Möglicherweise benötigen Sie eine Cascade Remove-Regel, um sicherzustellen, dass beim Entfernen eines Fahrzeugs auch die MovementData entfernt werden.

0voto

Rich Kroll Punkte 3945

Aus der von Ihnen geposteten Ausnahme geht hervor, dass die Tabelle in Ihrer Datenbank noch nicht erstellt worden ist ("Tabelle MOVEMENT_DATA nicht gefunden"). Wenn Sie Hibernate/JPA nicht angewiesen haben, Ihr Schema zu ändern, müssen Sie die Tabelle manuell hinzufügen, bevor Sie Ihren Code ausführen (ich glaube, es ist CREATE-UPDATE, um Hibernate anzuweisen, die Änderungen vorzunehmen).

0voto

topchef Punkte 17965

Definition der einbettbaren Klasse sollte nicht Referenz-Datenbanktabelle:

@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;
    }

    ...
}

Dann sollte die Fahrzeugeinheit eine Sekundärtabelle für die eingebettete Struktur definieren einschließlich Join-Spalte :

@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;
    }

    ...
}

Ich hoffe, dass dies für Sie funktioniert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X