2010-12-16 17 views
5

Estoy intentando crear dos entidades donde ambas entidades tienen embeddedIds. Una de las entidades tiene 2 referencias a la otra entidad, donde ambas referencias están relacionadas como ManyToOne.Java EE 6 JPA 2 La relación ManyToOne crea clave externa no válida

Los códigos de ejemplo se escriben a continuación;

@Embeddable 
public class ItemPK { 
    @Column(nullable = false, length = 100) 
    private String itemId; 
    @Column(name = "item_client_id", nullable = false) 
    private int clientId; 
    ... 
} 

@Entity 
@Table(name = "item") 
public class Item { 
    @EmbeddedId 
    private ItemPK id; 

    @ManyToOne 
    @JoinColumn(name = "item_client_id") 
    private Client client; 

    @OneToMany(mappedBy="item", cascade = CascadeType.ALL, orphanRemoval = true) 
    private Set<RelatedItem> relatedItems; 

    @OneToMany(mappedBy="relatedItem", cascade = CascadeType.ALL, orphanRemoval = true) 
    private Set<RelatedItem> relatedItemsRHS; 
    ... 
} 

@Embeddable 
public class RelatedItemPK { 
    @Column(name = "itemId", length = 100, nullable = false) 
    private String itemId; 
    @Column(name = "item_client_id", nullable = false) 
    private int clientId; 
    @Column(name = "relatedItemId", length = 100, nullable = false) 
    private String relatedItemId; 
    @Column(name = "related_item_client_id", nullable = false) 
    private int relatedItemClientId; 
    ... 
} 

@Entity 
@Table(name = "related_item") 
public class RelatedItem { 
    @EmbeddedId 
    private RelatedItemPK id; 

    @ManyToOne(cascade = CascadeType.ALL, optional = false) 
    @JoinColumns({ 
    @JoinColumn(name="itemId", referencedColumnName="itemId", insertable=false, updatable=false), 
    @JoinColumn(name="item_client_id", referencedColumnName="item_client_id", insertable=false, updatable=false) 
    }) 
    private Item item; 
    @ManyToOne(cascade = CascadeType.ALL, optional = false) 
    @JoinColumns({ 
    @JoinColumn(name="related_item_client_id", referencedColumnName="item_client_id", insertable=false, updatable=false), 
    @JoinColumn(name="relatedItemId", referencedColumnName="itemId", insertable=false, updatable=false) 
    }) 
    private Item relatedItem; 
    ... 
} 

El problema es que al crear claves foráneas para la entidad RelatedItem, obtuve una SQLException. Es la segunda relación ManyToOne que falla. La generación de SQL clave externa está por debajo,

ALTER TABLE related_item ADD CONSTRAINT FK_related_item_related_item_client_id FOREIGN KEY (related_item_client_id, relatedItemId) REFERENCES item (item_client_id, itemId) 

Desde tabla de elementos es indexado por primera vez por itemId luego por item_client_id, esta declaración hace que MySQL para producir un error.

me gustaría cambiar la ubicación de las columnas para que el SQL debe ser similar a la siguiente,

ALTER TABLE related_item ADD CONSTRAINT FK_related_item_relatedItemId FOREIGN KEY (relatedItemId, related_item_client_id) REFERENCES item (itemId,item_client_id) 

He intentado cambiar el orden de "s" JoinColumn pero el resultado no cambió. También intenté cambiar el nombre de los campos para comprobar si el proveedor de persistencia elige el orden por nombre de columna, pero de nuevo el resultado no cambió.

Entonces, ¿hay alguna manera de aplicar el orden de las columnas?

p.s. Yo uso siguientes cosas:

  • MySQL 5.1
  • EclipseLink 2.0.0
  • Java EE 6
  • JPA 2
  • GlassFish v3

Editar: EclipseLink produce después de SQL, que no se ejecuta;

CREATE TABLE related_item (SIMILARITY DOUBLE, widget_id INTEGER NOT NULL, relatedItemId VARCHAR(100) NOT NULL, itemId VARCHAR(100) NOT NULL, related_item_client_id INTEGER NOT NULL, item_client_id INTEGER NOT NULL, PRIMARY KEY (widget_id, relatedItemId, itemId, related_item_client_id, item_client_id)); 
CREATE TABLE item (IMAGEURL VARCHAR(2048), STATUS VARCHAR(64), URL VARCHAR(2048), PRICE DOUBLE, STOCK INTEGER, DESCRIPTION TEXT(64000), NAME VARCHAR(255), ITEMID VARCHAR(100) NOT NULL, item_client_id INTEGER NOT NULL, PRIMARY KEY (ITEMID, item_client_id)); 
ALTER TABLE related_item ADD CONSTRAINT FK_related_item_itemId FOREIGN KEY (itemId, item_client_id) REFERENCES item (itemId, item_client_id); 
ALTER TABLE related_item ADD CONSTRAINT FK_related_item_related_item_client_id FOREIGN KEY (related_item_client_id, relatedItemId) REFERENCES item (item_client_id, itemId); 
ALTER TABLE item ADD CONSTRAINT FK_item_item_client_id FOREIGN KEY (item_client_id) REFERENCES client (ID); 
+0

¿Cuál es el error? El orden del campo en la restricción no debería tener ningún efecto.(también incluye el SQL generado para producir el error. – James

+0

El orden de las restricciones es importante en MySQL. Debe haber un índice correspondiente en la tabla de destino donde la primera clave del índice es igual a la primera columna en la lista de restricciones. – bdaylik

Respuesta

1

Por favor, incluya la pila de rastreo. Sin embargo, le recomiendo que se salte las etiquetas @JoinColumn a menos que tenga un MUY buen motivo para especificar las claves externas usted mismo. Al especificar el atributo mappedBy en una de las direcciones, JPA puede averiguar qué hacer por sí mismo.

Java EE 6 y JPA ponen mucho esfuerzo en habilitar Convención sobre configuración, lo que significa que la mayoría de las veces, las cosas funcionarán de la caja. Es deseable para usted, el programador, porque tiene menos código de placa de caldera de qué preocuparse, y es deseable para los implementadores de contenedores JPA y Jave EE porque les da libertad para elegir las soluciones de mejor rendimiento. Al declarar usted mismo las relaciones con la clave externa, le roba a usted y a JPA esta ventaja.

Editar: De hecho, sospecho que tanto la especificación de mappedBy como la especificación de @JoinTable podrían ser la causa raíz de su problema. Pero necesito ver el rastro de la pila para contarlo con certeza.

+0

Estoy usando mappedBy y @JoinColumns en muchos lugares diferentes, pero este es el único que tengo problemas. BTW: Intenté eliminar @JoinColumns pero obtuve la siguiente excepción, Existen varias asignaciones de escritura para el campo [related_item.item_client_id]. Solo uno puede definirse como de escritura, todos los demás deben ser de solo lectura. y no conozco otra forma de especificar un campo de solo lectura. – bdaylik

0

El orden de las columnas no debería importar. Si lo hace, puede cambiar el orden en su índice para que coincida, o cambiar el orden en el que aparece su clave principal, o simplemente usar sus scripts para generar su DDL.

Cuestiones relacionadas