JPA - Повернення автоматично згенерованого ідентифікатора після збереження ()


113

Я використовую JPA (EclipseLink) та Spring. Скажіть, у мене є проста особа з автоматично створеним ідентифікатором:

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

     // ...
}

У своєму класі DAO у мене є метод вставки, який викликає persist()цю сутність. Я хочу, щоб метод повернув згенерований ідентифікатор для нової сутності, але коли я тестую його, він повертається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
Nayan Wadekar

Дякую за відповіді. І як складне рішення (не JPA), ми можемо використовувати інший унікальний ідентифікатор, наприклад, часова мітка unix.
sura2k

1
можливий дублікат " Коли JPA встановлює @GeneratedValue @Id
Raedwald

Відповіді:


184

Ідентифікатор може бути згенерований лише під час змиву. Залишається суб'єкт господарювання лише робить його "прив'язаним" до контексту стійкості. Отже, будь-ласка, змийте менеджера сутності чітко:

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

або повернути сутність, а не її ідентифікатор. Коли транзакція закінчується, вимивання відбудеться, і користувачі суб'єкта поза транзакцією таким чином побачать згенерований ідентифікатор у суті.

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

10
Примітка: для цього потрібно помацати поле id @GeneratedValue- все, що це означає
Mr_and_Mrs_D

Може у ласка , поясніть проблеми, намагаючись домогтися цього з композитним ід stackoverflow.com/questions/31362100 / ...
bl3e

Чи існує покарання за ефективність (або будь-які інші негативні наслідки) промивання вручну після збереження?
Крейг Отіс

3
Так, є: непотрібне зворотне звернення до бази даних, якщо транзакція закінчується відхиленням, можливі винятки, якщо зберігається суб'єкт (або інші об'єкти, що промили) ще не має дійсного стану. Генератор послідовностей або uuid простіший і ефективніший, і не має цих проблем, оскільки ідентифікатор генерується та присвоюється перед записом сутності в базу даних.
JB Nizet

1
@JBNizet, вам потрібно повернути екземпляр чи все-таки дійсна посилання все-таки є дійсною? Я маю на увазі, чи insertABCстворює новий об’єкт? Або модифікувати стару?
ryvantage

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();

Не працює, даючи нуль як повернення після збереження даних у таблицю. або оновлення не працює в цьому випадку. Що мені робити для цього? підкажіть, будь ласка, спосіб ... Дякую
Вікрант Каш'яп

1
@VikrantKashyap Будь ласка, опублікуйте нове запитання з невеликим кодом та згадайте мене, щоб я міг подивитися.
Корай Тугай

2

Ви також можете використовувати GenerationType.TABLE замість IDENTITY, який доступний лише після вставки.


2
Просто слово обережності. Коли я спробував GenerationType.TABLE, він створив окрему таблицю під назвою hibernate_sequences і перезапустив послідовність з 1.
SriSri

0

Ще один варіант, сумісний з 4.0:

Перш ніж здійснити зміни, ви можете відновити новий CayenneDataObjectоб’єкт із колекції, пов’язаної з контекстом, наприклад:

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

потім перейдіть до ObjectIdкожного з колекцій, наприклад:

ObjectId objectId = dataObject.getObjectId();

Нарешті, ви можете перебрати значення під значеннями, де зазвичай згенерований ідентифікатор буде першим із значень (для одного ключа стовпця) на Картах, що повертається getIdSnapshot(), він також містить ім'я стовпців (ів), пов’язані з ПК як ключ (и):

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).
Ібрагім Дауда
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.