JPA-persist()の後に自動生成されたIDを返す


113

JPA(EclipseLink)とSpringを使用しています。自動生成されたIDを持つ単純なエンティティがあるとします。

@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;

     // ...
}

私のDAOクラスには、persist()このエンティティを呼び出すinsertメソッドがあります。メソッドで新しいエンティティの生成されたIDを返したいのですが、テストすると、0代わりに返されます。

public class ABCDao {
    @PersistenceContext
    EntityManager em;

    @Transactional(readOnly=false)
    public int insertABC(ABC abc) {
         em.persist(abc);
         // I WANT TO RETURN THE AUTO-GENERATED ID OF abc
         // HOW CAN I DO IT?
         return abc.id; // ???
    }
}

DAOをラップするサービスクラスもあります(違いがある場合)。

public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         return abcDao.insertABC(abc);
    }
}

同様のものは、stackoverflow.com
q / 3328813/366964を

答えてくれてありがとう。(JPAではなく)トリッキーなソリューションとして、UNIXタイムスタンプのような別の一意のIDを使用できます。
sura2k 2012年

回答:


184

IDは、フラッシュ時にのみ生成されることが保証されています。エンティティを永続化すると、エンティティが永続コンテキストに「アタッチ」されるだけです。したがって、エンティティマネージャーを明示的にフラッシュします。

em.persist(abc);
em.flush();
return abc.getId();

または、IDではなくエンティティ自体を返します。トランザクションが終了すると、フラッシュが発生し、トランザクション外のエンティティのユーザーには、エンティティで生成されたIDが表示されます。

@Override
public ABC addNewABC(ABC abc) {
    abcDao.insertABC(abc);
    return abc;
}

10
注意:これはidフィールドに注釈を付ける必要があります@GeneratedValue-必要なものは何でも
Mr_and_Mrs_D

Uは、複合のidでこれを達成しようとする際に問題を説明していただけますstackoverflow.com/questions/31362100/...
bl3e

永続化した後に手動でフラッシュすると、パフォーマンスが低下しますか(またはその他の悪影響がありますか)?
Craig Otis

3
はい、あります。トランザクションがロールバックされてしまうと、データベースへの不要なラウンドトリップが発生します。永続化されたエンティティ(または他のフラッシュされたエンティティ)がまだ有効な状態にない場合は、例外が発生する可能性があります。シーケンスまたはuuidジェネレーターは、エンティティがデータベースに書き込まれる前にIDが生成され割り当てられるため、よりシンプルで効率的であり、これらの問題はありません。
JB Nizet

1
@JBNizet、インスタンスを返す必要がありますか、それとも渡された参照はまだ有効ですか?つまり、insertABC新しいオブジェクトを作成しますか?または古いものを変更しますか?
ryvantage 2016年

13
@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;   
}

エンティティクラスに@GeneratedValue表記があることを確認してください。これにより、エンティティプロパティの自動生成動作がJPAに通知されます


4

これは私がそれをした方法です:

EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(object);
transaction.commit();
long id = object.getId();
entityManager.close();

データをテーブルに永続化した後、戻り値としてゼロを与えて機能しません。この場合、どちらの更新も機能しません。これを行うにはどうすればよいですか。方法を提案してください...ありがとう
Vikrant Kashyap

1
@VikrantKashyap小さなコードで新しい質問を投稿し、私に説明してください。
Koray Tugay

2

挿入後にのみ使用できるIDENTITYの代わりにGenerationType.TABLEを使用することもできます。


2
注意の言葉。私はGenerationType.TABLEを試したとき、それはhibernate_sequencesという名前の別のテーブルを作成し、1からシーケンスを再スタート
SriSri

0

4.0と互換性のある別のオプション:

変更をコミットする前にCayenneDataObject、次のように、コンテキストに関連付けられたコレクションから新しいオブジェクトを回復できます。

CayenneDataObject dataObjectsCollection = (CayenneDataObject)cayenneContext.newObjects();

次にObjectId、次のように、コレクション内のそれぞれにアクセスします。

ObjectId objectId = dataObject.getObjectId();

最後に、値で反復することができます。通常、generated-idはgetIdSnapshot()、によって返されるマップ内の値(単一列キーの場合)の最初の値になります。これには、PKに関連付けられた列名も含まれますキーとして:

objectId.getIdSnapshot().values()

0

これは私がやった方法です。あなたが試すことができます

    public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         ABC.setId(0);
         return abcDao.insertABC(abc);
    }
}

-3
em.persist(abc);
em.refresh(abc);
return abc;

この方法ではうまくいきませんでした。このエラーが発生しました:javax.persistence.PersistenceException:org.hibernate.HibernateException:このインスタンスはまだデータベースの行として存在していません]
rtcarlson

@rtcarlson、はい、これは機能しません。新しいオブジェクトを作成する場合、必要なものはありem.flush()ませんem.refresh(abc)
Ibrahim Dauda、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.