Domanda

Nelle tabelle del database legacy abbiamo colonne numerate come C1, C2, C3, C100 o M1, M2, M3, M100.
Queste colonne rappresentano i dati BLOB.

Non è possibile modificare nulla in questo database.

Utilizzando JPA Embeddable mappiamo tutte le colonne su singoli campi.Quindi durante l'incorporamento sovrascriviamo i nomi utilizzando 100 annotazioni di sovrascrittura.

Recentemente siamo passati all'ibernazione e ho trovato cose come Tipo di raccolta utente E Tipo utente composito.Ma non avevo trovato casi d'uso vicini ai miei.

È possibile implementare alcuni tipi di utente utilizzando Hibernate per poter mappare un insieme di colonne in una raccolta senza ulteriori interrogazioni?

Modificare:
Come probabilmente avrai notato, i nomi delle colonne possono differire da tabella a tabella.Voglio creare un tipo come "LegacyArray" senza la necessità di specificare tutte le @Columns ogni volta che utilizzo questo tipo.Ma invece userei

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "A"),
      @Parameter(name = "size", value = "128")
   })
   List<Integer> legacyA;

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "B"),
      @Parameter(name = "size", value = "64")
   })
   List<Integer> legacyB;
È stato utile?

Soluzione

Posso pensare ad un paio di modi in cui lo farei.

1.Crea viste per le informazioni sulla raccolta che simulano una struttura di tabella normalizzata e mappala su Hibernate come raccolta:

Supponendo che venga chiamata la tabella esistente primaryentity, creerei una vista simile alla seguente:

-- untested SQL...
create view childentity as
(select primaryentity_id, c1 from primaryentity union
select primaryentity_id, c2 from primaryentity union
select primaryentity_id, c3 from primaryentity union
--...
select primaryentity_id, c100 from primaryentity)

Ora, dal punto di vista di Hibernate, childentity è solo una tabella normalizzata che ha una chiave esterna primarykey.La mappatura di questo dovrebbe essere abbastanza semplice ed è trattata qui:

I vantaggi di questo approccio:

  • Dal punto di vista di Hibernate, le tabelle sono normalizzate, è una mappatura abbastanza semplice
  • Nessun aggiornamento alle tabelle esistenti

Gli svantaggi:

  • I dati sono di sola lettura, non credo che la tua vista possa essere definita in modo aggiornabile (potrei sbagliarmi)
  • Richiede modifiche al database, potrebbe essere necessario creare molte visualizzazioni

In alternativa, se il tuo DBA non ti consente nemmeno di aggiungere una vista al database o se devi eseguire aggiornamenti:


2.Usa Hibernate funzione di mappatura del modello dinamico per mappare le tue proprietà C1, C2, C3 su a Carta geografica, e avere del codice per te DAO layer esegue la conversazione appropriata tra la proprietà Map e Collection:

Non l'ho mai fatto personalmente, ma credo che Hibernate ti permetta di mappare le tabelle su HashMaps.Non sono sicuro di quanto dinamicamente Hibernate ti permetta di farlo (ad esempio, puoi cavartela semplicemente specificando il nome della tabella e facendo in modo che Hibernate mappi automaticamente tutte le colonne?), ma è un altro modo in cui posso pensare di farlo.

Se segui questo approccio, assicurati di utilizzare il file oggetto di accesso ai dati pattern e garantire che l'implementazione interna (uso di HashMaps) sia nascosta dal codice client.Assicurati inoltre di controllare prima di scrivere nel database che la dimensione della tua raccolta non superi il numero di colonne disponibili.

I vantaggi di questo approccio:

  • Nessuna modifica al database
  • I dati sono aggiornabili
  • La mappatura O/R è relativamente semplice

Gli svantaggi:

  • Molti collegamenti idraulici nel livello DAO per mappare i tipi appropriati
  • Utilizza funzionalità di ibernazione sperimentali che potrebbero cambiare in futuro

Altri suggerimenti

Personalmente, penso che il design suona come si rompe prima forma normale per i database relazionali. Che cosa succede se avete bisogno C101 o M101? Cambiare di nuovo lo schema? Penso che sia molto invadente.

Se si aggiunge Hibernate per il mix è ancora peggio. L'aggiunta C101 o M101 significa dover modificare le vostre oggetti Java, le mappature Hibernate, tutto.

Se si dispone di 1: m rapporti con tabelle C e M, devi essere in grado di gestire i casi ho appena citato con l'aggiunta di ulteriori righe. I suoi oggetti Java contengono Collection o Collection . Le mappature Hibernate sono uno-a-molti che non cambiano.

Forse il motivo per cui non si vede alcun esempio di Hibernate per abbinare il vostro caso, perché è un progetto che non è raccomandato.

Se è necessario, forse si dovrebbe guardare a Hibernate Mapping Componente .

UPDATE: Il fatto che questa è l'eredità è preso atto. Il mio punto nel portare prima forma normale è tanto per gli altri che potrebbero trovare questa domanda in futuro come lo è per la persona che ha pubblicato la domanda. Non vorrei rispondere alla domanda in modo tale che in silenzio ha affermato questo progetto come "buono".

Sottolineando mappatura componente Hibernate è pertinente perché conoscere il nome di quello che stai cercando può essere la chiave quando si sta cercando. Hibernate permette un modello a oggetti di essere a grana più fine rispetto al modello relazionale che le mappe. Siete liberi di modellare uno schema denormalizzato (ad esempio, nome e indirizzo oggetti come parte di un oggetto persona più grande). Questo è solo il nome che danno una tale tecnica. Potrebbe aiutare a trovare altri esempi come bene.

Scusate se sto equivoco il problema qui, io non ne so molto di Hibernate. Ma non potevi solo concatenare durante la selezione dal database per ottenere qualcosa di simile a ciò che si vuole?

Come:

SELECT whatever
     , C1||C2||C3||C4||...||C100 AS CDATA
     , M1||M2||M3||M4||...||M100 AS MDATA
FROM ...
WHERE ...

(Naturalmente, l'operatore di concatenazione differisce tra RDBMS.)

[EDIT] suggerisco di usare un CompositeUserType. Ecco un esempio . V'è anche un buon esempio a pagina 228f nel libro "Java Persistence con Hibernate".

Che ti permette di gestire le molte colonne come un singolo oggetto in Java.

La mappatura è simile al seguente:

@org.hibernate.annotations.Columns(columns = {
    @Column(name="C1"),
    @Column(name="C2"),
    @Column(name="C3"),
    ...
})
private List<Integer> c;

Sospensione caricherà tutte le colonne contemporaneamente durante la query normale.

Nel tuo caso, è necessario copiare i valori int dalla lista in un numero fisso di colonne in nullSafeSet. Pseudocodice:

for (int i=1; i<numColumns; i++)
    if (i < list.size())
        resultSet.setInt(index+i, list.get(i));
    else
        resultSet.setNull(index+i, Hibernate.INTEGER.sqlType());

In nullSafeGet è necessario creare un elenco e fermare l'aggiunta di elementi quando una colonna è NULL. Per una maggiore sicurezza, vi suggerisco di creare una propria implementazione lista che non permette di crescere oltre il numero di colonne (ereditare da ArrayList e di override ensureCapacity()).

[EDIT2] Se non si desidera digitare tutte le annotazioni @Column, utilizzare un generatore di codice per loro. Questo può essere semplice come script che si dà un nome e un numero e viene stampato @Column (...) per System.out. Dopo che lo script ha funzionato, solo tagliare e incollare i dati nella sorgente.

L'unica altra soluzione sarebbe quella di accedere alle API di Hibernate interna per costruire che le informazioni in fase di esecuzione, ma che API è interna, quindi un sacco di roba è privato. È possibile utilizzare la riflessione Java e setAccessible(true) ma che il codice probabilmente non sopravvivere al prossimo aggiornamento di Hibernate.

È possibile utilizzare UserTypes per mappare un determinato numero di colonne da qualsiasi tipo che si desidera. Questo potrebbe essere una raccolta, se (ad esempio) per le collezioni sono sempre delimitate in dimensioni da un numero noto di oggetti.

E 'passato un po' (> 3 anni) da quando ho usato Hibernate quindi sono abbastanza arrugginito, ma mi ricordo che sia molto facile da fare; la classe BespokeUserType viene passato il ResultSet a idrato l'oggetto da esso.

Anche io ho mai usato Hibernate.

Suggerisco a scrivere un piccolo programma in un linguaggio interpretato (come Python ) in cui è possibile eseguire un stringa come se si trattasse di un comando. Si potrebbe costruire una dichiarazione che prende il lavoro noioso di fare quello che si vuole fare manualmente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top