2015-03-21 9 views
5

Ho una tabella di clienti, ogni cliente appartiene a un'azienda, le aziende vogliono che i numeri dei clienti inizino a 0 e aumentino man mano che aggiungono clienti e quando la societàB aggiunge un cliente, I numeri dei clienti dell'azienda non dovrebbero essere influenzati. CustomerId internamente può essere qualsiasi numero, customerNumber deve essere incrementato gap-free nel contesto di companyId (con gap-free intendo 0,1,2,3,4, se 2 è cancellato, è sparito, il prossimo inserto dovrebbe essere 5 e non 2)Come creare un generatoreNumero cliente per ogni azienda in Hibernate

Example: 
    companyId customerNumber customerId 
    0   0    0 
    0   1    1 
    0   2    2 
    0   3    3 
    0   4    4 
    0   5    5 
    1   0    6 
    1   1    7 
    1   2    8 

mi chiedevo se c'è un modo migliore per farlo che l'apertura di una transazione, trovando il massimo CustomerNumber, l'inserimento di una voce con il massimo + 1 come CustomerNumber e chiusura delle transazioni

C'è una sorta di annotazione che posso usare dove posso specificare i criteri per generare un customerNumber? Il prossimo numero cliente dovrebbe essere il numero più alto disponibile all'interno dell'azienda. (Ho circa 20 altre entità che hanno requisiti di identificazione incrementale leggibili dall'uomo simili basati su data e comapnyId e voglio rendere la generazione di campi di tipo CustomerNumber il più possibile a prova di errore, non voglio dover ricordare di farlo ogni volta che persistono una nuova entità)

Qualcosa di simile:

@SequenceGenerator(uniqueOver="companyId,customerNumber",strategy=GenerationType.AUTO) 
private Long customerNumber; 

La soluzione deve essere compatibile ACID dal momento che sto lavorando con magazzino e dati finanziari.

Aggiornamento: Ho rinominato id a customerId e customerId a customerNumber per evitare confusione.

Aggiornamento: Quando dico senza gap, voglio dire che customerNumbers dovrebbero essere 0,1,2,3,4,5,6,7,8,9 - se elimino il numero 4 è andato per sempre e il successivo inserimento dovrebbe essere di 10 a meno che non creo una nuova società, allora il loro primo cliente dovrebbe iniziare a 0.

Aggiornamento: sto usando la primavera con Hibernate, quindi l'annotazione @PrePersist non funziona per me. Se @PrePersist è suggerita come una soluzione, quindi ha bisogno di lavorare sotto la molla, quindi una risposta per la domanda di Simon sarebbe necessaria: Enable @PrePersist and @PreUpdate in Spring

risposta suggerita, che io non sono sicuro:

@Entity 
@Table(name = "Customer") 
public class Customer { 

    @Table(name = "CustomerNumber") 
    @Entity(name = "sequenceIdentifier") 
    public static class CustomerNumberSequenceIdentifier { 

     @Id 
     @GenericGenerator(name = "sequence", strategy = "sequence", parameters = { 
       @org.hibernate.annotations.Parameter(name = "sequenceName", value = "sequence"), 
       @org.hibernate.annotations.Parameter(name = "allocationSize", value = "1"), 
     }) 
     @GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE) 
     private Long id; 

    } 


    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long customerId; 

    @ManyToOne 
    private Company company; 

    @GeneratedValue(generator = "sequenceIdentifier", strategy=GenerationType.TABLE) 
    private Long customerNumber 

} 

risposta

1

Se si utilizza Hibernate; Esempio Query

Query query = session.createQuery("insert into customer (company_id, customer_id)" +"(select :company_id, IFNULL(max(customer_id),1)+1 from customer where company_id = :company_id)");

//set the company_id here 

    int result = query.executeUpdate(); 

Nota: IFNULL è una sintassi specifica MYSQL

Suggerisco di tenere il campo società id auto_increment in una tabella master società separata.

2

Mentre non posso parlare con il lato di sospensione delle cose (sorry), è possibile eseguire questa con un tavolo in MySQL fin tanto che utilizza il motore MyISAM, con la seguente struttura della tabella:

create table ai_test (
    company_id integer, 
    customer_number integer auto_increment, 
    primary key (company_id, customer_number) 
) engine=MyISAM; 

Ecco af iddle che mostra che in azione: http://sqlfiddle.com/#!9/45e78/1

Spiacente, non riesco a tradurre questo in ibernazione per te - mai usato, ma questo potrebbe essere un punto di partenza.

modificare
in quanto è richiesta Inno, è possibile utilizzare questa tabella e trigger:

create table ai_test (
    company_id integer, 
    customer_number integer, 
    primary key (company_id, customer_number) 
) engine=InnoDB; 


create trigger inno_composite_ai_ok before insert on ai_test 
for each row 
begin 
    set new.customer_number =  
     (select ifnull((select max(customer_number)+1 
         from ai_test 
          where 
         company_id=new.company_id),1)); 
end// 

Ecco un violino di esempio per voi: http://sqlfiddle.com/#!9/fffd0/14

modificare
One more aggiornamento per includere il requisito della singola colonna PK

create table ai_test (
    company_id integer, 
    customer_no integer, 
    customer_id integer primary key auto_increment 

) engine=InnoDB; 

create trigger inno_composite_ai_ok before insert on ai_test 
for each row 
begin 
    set new.customer_no =  
     (select ifnull((select max(customer_no)+1 
         from ai_test 
          where 
         company_id=new.company_id),1)); 
end// 

fiddle here

Nota È possibile (e probabilmente dovrebbe) mettere un vincolo univoco in company_d/customer_no

1

Stai cercando una generazione del numero di sequenza senza dover scrivere il ddl per generare un nuovo numero di sequenza per ogni tabella. Eseguire questa operazione con una tabella dei numeri di sequenza separata e creare una selezione per la transazione di aggiornamento per bloccare entrambe le tabelle per l'inserimento. Hibernate fa questo con le tabelle avanzate.

Ecco un buon esempio: http://vladmihalcea.com/hibernate-identity-sequence-and-table-sequence-generator/

Scorrere verso il basso fino alla sezione TABELLA (sequenza), che è una tabella di soluzione di numeri di sequenza.

Nell'esempio è sufficiente specificare il nome del cliente come nome della sequenza per ottenere la sequenza corretta.

Il sovraccarico genera una sequenza di righe per ogni nuova azienda e il blocco della tabella per ogni nuovo cliente.

+0

La classe TableSequenceIdentifier, presumo che sarebbe, nel mio caso, la classe Customer? Come posso ottenere i numeri dei clienti per azienda utilizzando l'esempio della sequenza di tabelle? –

+0

La classe identificatore sequenza di tabelle è una tabella separata che memorizza solo i valori di sequenza per i clienti. Terrà il companyid e il prossimo valore di sequenza per quella società. Hibernate fornisce tabelle avanzate per eseguire la selezione per la strategia di aggiornamento/aggiornamento per avvolgere la transazione di inserimento. Questo ti dà un aggiornamento sequenziale sicuro. L'inserto della tabella clienti ora si baserà sulla classe di identificatore della sequenza della tabella. – user1442498

+0

Non sto seguendo abbastanza ... Ho aggiornato la mia domanda, customerId è un campo autoincrementante, ogni azienda può avere più clienti e ogni numero cliente dovrebbe essere incrementato per azienda. La mia classe CustomerNumberSequenceIdentifier è corretta per ciò che sto cercando di fare e come posso inserirla in CustomerNumber in modo tale da ottenere numeri di clienti che aumentano per azienda come nell'esempio sopra riportato? Gli esempi che sto trovando mostrano semplicemente come la tabella dei numeri di sequenza stia generando sequenze. Sentiti libero di modificare il modello di ibernazione nella mia domanda e riempi gli spazi vuoti. –