2011-02-02 11 views
7

Używam Toplink WZP-essential i SQL Server 2008Dlaczego JPA persist() nie generuje głównego pierwotnego ID?

Moim celem jest uzyskanie automatycznego przyrostu pierwotną wartość klucza danych, który ma być wstawiony do tabeli. Wiem, że w JDBC istnieje metoda getInsertedId(), która daje identyfikator automatycznego przyrostowego identyfikatora głównego (ale to jest po wykonaniu instrukcji insert).

W JPA dowiedziałem się, że @GenratedValue annotation może załatwić sprawę.

@Entity 
@Table(name = "tableOne") 
public class TableOne implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    @Basic(optional = false) 
    @Column(name = "tableId") 
    private Integer tableId; 

Teraz, jeśli mogę uruchomić poniższy kod powinien dać mi auto zwiększane id ale zwraca NULL ...

EntityManager em = EmProvider.getInstance().getEntityManagerFactory().createEntityManager(); 
EntityTransaction txn = em.getTransaction(); 
txn.begin(); 

TableOne parent = new TableOne(); 
em.persist(parent); //here I assume that id is pre-generated for me. 
System.out.println(parent.getTableId()); //this returns NULL :(
+0

Mogę uzyskać id uzyskanego, jeśli commit: em.getTransaction(). Commit(), ale nie ma sposobu, aby uzyskać id już z persist? hmm –

+0

Twój kod powinien działać zgodnie z oczekiwaniami. Przetestowałem to i otrzymałem identyfikator przed zatwierdzeniem lub jeśli następnie wycofałem. Dziwne, że tak nie jest. – Joel

+0

Czy robi różnicę, jeśli tableId jest int, a nie Integer? – Joel

Odpowiedz

2

Jesteśmy również za pomocą SQL Server 2008 i je nigdy nie pracował dla mnie, więc zawsze wykonuję oddzielne zapytanie "SELECT @@IDENTY", aby uzyskać wstawiony identyfikator.

Powodem, dla którego znalazłem w sieci było to, że identyfikator automatyczny (IDENTITY) jest zarządzany przez bazę danych i nigdy nie został pobrany w Entity, dopóki nie zostanie zatwierdzony wiersz lub ręcznie pobrane informacje z bazy danych.

+0

Masz na myśli, ponieważ SQL Server 2008, nie możemy użyć @ GeneratedValue.Sequence lub Table or Identity ??? Doszedłem do wniosku, że musiałem najpierw przepłukać (wstawić wywołanie do db, aby uzyskać wygenerowany identyfikator), ale moim celem jest bez wywoływania wstawiania, jeśli mogę uzyskać identyfikator podstawowy. –

+0

Być może masz rację, dokument nie zawiera listy SQL Server obsługującej obiekt SEQUENCE .... "Obiekty sekwencji używają specjalnych obiektów bazy danych do generowania identyfikatorów. Obiekty sekwencji są obsługiwane tylko w niektórych bazach danych, takich jak Oracle, DB2, i Postgres. " http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Table_sequencing –

+0

oznaczanie jako odpowiedź, SEQUENCE nie jest obsługiwany przez SQL Server –

11

Problem polega na użyciu generowania identyfikatorów IDENTITY. Generacja identyfikatorów IDENTITY nie może wykonać wstępnej alokacji, ponieważ wymagają one INSERT do wygenerowania id. Generowanie identyfikatorów TABELA i SEQUENCE obsługuje wstępną alokację i zawsze zalecałbym ich używanie i nigdy nie używałbym TOŻSAMOŚCI z powodu tego problemu i wydajności.

Możesz wyzwolić identyfikator, który będzie generowany, gdy generowanie identyfikatora IDENTITY zostanie wygenerowane przez wywołanie flush().

+0

sekwencja hmmm nie działa dla mnie. Zmieniono moją adnotację w klasie encji na: '@Id @SequenceGenerator (name =" seq ", sequenceName =" seq ") @GeneratedValue (strategy = GenerationType.SEQUENCE, generator = "seq") ' –

+1

Następnie po em.persist (myBean); int insertedId = myBean.getId(); To getId() zwraca zero ... czy robię coś nie tak? –

+1

To jest problem z timingiem. JPA nie wstawił danych podczas próby uzyskania wartości identyfikatora. Musisz przepłukać, aby zaczął robić modyfikacje w bazie danych. Potem masz identyfikator. Lepiej byłoby, gdyby JPA dokonywał modyfikacji w bazie danych podczas wywoływania metody getId(). –

6

po prostu to zrobić:

public void create(T entity) { 
    getEntityManager().persist(entity); 
    getEntityManager().flush(); 
    getEntityManager().refresh(entity); 
} 

Po odświeżeniu podmiot masz pole ID z odpowiednią wartością.

+3

Powodem dodania 'flush()' jest to, że 'persist()' nie jest wyraźnie gwarantowane, że wygenerowało '@ GeneratedValue', ale musi być wygenerowane na lub przed' flush() '. Zobacz to pytanie: http://stackoverflow.com/questions/9087848/when-does-the-jpa-set-a-generatedvalue-id – Raedwald

Powiązane problemy