2009-09-17 6 views
1

Je travaille sur un mappage d'entité Hibernate pour une vue de base de données; quand je fais une requête de critères, hibernate génère un mauvais SQL. Toute aide pour déterminer quel est le problème avec ma cartographie serait grandement appréciée!Wrong SQL pour l'objet de vue utilisant les annotations Hibernate

J'ai deux entités mappées que j'essaye de saisir d'une vue de base de données; la vue n'a pas d'autres colonnes, juste le FK de chaque entité. L'un de ces FK peut être traité comme une clé primaire, puisque la vue a une ligne pour chaque entité primaire. Donc, mon schéma de DB pour la vue ressemble à:

primary(primary_id, some_other_fields) 
history(history_id, primary_id, some_other_fields) 
view_latest_status_history(primary_id, history_id) 

Notez la vue est utilisée parce que je veux choisir que la dernière histoire pour chaque primaire, tous cartographiés documents historique. Voici l'objet que je me sers de la vue, avec des annotations d'entité:

@Entity 
@org.hibernate.annotations.Entity(dynamicUpdate = true) 
@Table(name = "view_latest_status_history") 
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) 
public class ViewLatestStatusHistoryRow implements Serializable { 
    private Primary primary; 
    private History history; 

    /** 
    * @return Returns the history. 
    */ 
    @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY) 
    @JoinColumn(name = "history_id", nullable = true) 
    @AccessType("field") 
    public History getHistory() { 
     return history; 
    } 

    //equals() and hashCode() implementations are omitted 

    /** 
    * @return Returns the primary. 
    */ 
    @Id 
    @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY) 
    @JoinColumn(name = "primary_id", nullable = false) 
    @AccessType("field") 
    public Primary getPrimary() { 
     return primary; 
    } 
} 

Les deux objets principaux et l'histoire ont terminé, le travail des annotations d'entité.

Ma configuration de vos critères:

criteria.add(Restrictions.in("primary", [collection of primary objects])); 
criteria.setFetchMode("primary", FetchMode.JOIN); 
criteria.setFetchMode("history", FetchMode.JOIN); 

Et le (mauvais) générés SQL:

select this_.primary as primary78_1_, this_.primary_id as prim2_78_1_, primary2_.history_id as unique1_56_0_, ...history fields 
from DB_CATALOG.dbo.view_latest_status_history this_ 
left outer join DB_CATALOG.dbo.history primary2_ on this_.primary_id=primary2_.primary_id 
where this_.specChange in (?, ?...) 

Je pourrais ai sali jusqu'à quelques petites choses lors de l'édition sur les détails de notre projet de schéma DB, mais le point est le premier champ dans la clause 'select' est faux:

this_.primary (view_latest_status_history.primary) n'est pas un champ; le champ devrait s'appeler primary_id. Je pense que cela peut avoir quelque chose à voir avec l'annotation @Id sur le champ primaire? Une idée de comment réparer ça? Si je supprime le @Id, j'obtiens une erreur me disant que l'entité n'a pas de clé primaire.

Mise à jour:

Je aucune carte plus la vue comme un champ en utilisant une notation de table de jointure (comme suggéré ci-dessous). Les annotations ont été révisées comme suit. Cette solution fonctionne correctement dans HQL et génère le schéma attendu lorsque hbm2ddl est activé, mais je ne l'ai pas testé de nouveau à l'aide de la requête de critères.

@Entity 
@Table(name = "view_latest_status_history") 
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
public class ViewLatestStatusHistoryRow implements Serializable { 
    private String id; 
    private Primary primary; 
    private History history; 

    /** 
    * @return Returns the history. 
    */ 
    @OneToOne(optional = true) 
    @JoinColumn(name = "history_id", nullable = true) 
    @AccessType("field") 
    public History getHistory() { 
     return history; 
    } 

    //equals() and hashCode() implementations are omitted 

    @Id 
    @Column(name = "primary_id", nullable = false) 
    @Override 
    @AccessType(value = "field") 
    public String getId() { 
     return id; 
    } 

    /** 
    * @return Returns the primary. 
    */ 
    @PrimaryKeyJoinColumn(name = "primary_id", referencedColumnName = "unique_id") 
    @OneToOne(optional = false) 
    @AccessType("field") 
    public Primary getPrimary() { 
     return primary; 
    } 
} 

Répondre

1

Il est très certainement due à @Id annotation - primary_id n'est pas une clé primaire dans ce cas. Vous ne pouvez pas non plus avoir @Id et @ManyToOne sur la même propriété. Permettez-moi de vous poser la question suivante: pourquoi mappez-vous ViewLatestStatusHistoryRow en tant qu'entité pour commencer? Ce n'est pas comme si tu allais persister. Envisagez de mapper votre entrée d'historique la plus récente directement (en lecture seule) sur le serveur principal (en tant que plusieurs en un) et en utilisant votre vue en tant que table de jointure.

+0

Je vais essayer de le mapper au primaire, et marquer comme réponse si cela fonctionne! Merci pour la réponse rapide. Savez-vous comment je traiterais cela dans le cas général pour une vue avec d'autres domaines? Et aussi comment je peux assurer que la propriété est mise à jour sur l'objet primaire quand un nouvel (dernier) historique est ajouté? – RMorrisey

+0

La propriété n'aura pas besoin d'être mise à jour car vous ne la conserverez pas. Vous devez le mapper en utilisant JoinTable: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#d0e1177 En ce qui concerne "view with fields", si vous avez besoin pour le mapper, vous devez le mapper en tant qu'entité.Cela signifie avoir une ** clé ** réelle ** plutôt que quelque chose qui arrive à être unique :-) Vous pouvez utiliser l'ID composite pour mapper PK qui se compose de plusieurs colonnes, mais cela peut avoir des effets secondaires laids. Regardez les documents Hibernate pour les identifiants composites pour plus de détails. – ChssPly76

+0

Cela me permet d'éliminer le problème de sélection n + 1 et d'accélérer considérablement le traitement par lots pour quelques milliers de primaires. Merci =) – RMorrisey

Questions connexes