JPA - Возврат автоматически сгенерированного идентификатора после сохранения()

Я использую JPA (EclipseLink) и Spring. Скажем, у меня есть простой объект с автогенерированным идентификатором:

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

     // ...
}

В моем классе DAO у меня есть метод insert, который вызывает 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);
    }
}

Ответ 1

Идентификатор гарантированно генерируется только во время очистки. Сохранение сущности только делает ее "прикрепленной" к контексту персистентности. Таким образом, либо очистите менеджера объектов явно:

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

или вернуть сам объект, а не его идентификатор. Когда транзакция закончится, произойдет флеш, и пользователи сущности вне транзакции, таким образом, получат сгенерированный идентификатор в сущности.

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

Ответ 2

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

проверьте, что в классе сущности присутствует нотация @GeneratedValue. Это говорит JPA о вашем автогенерированном поведении объекта

Ответ 3

Вот как я это сделал:

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

Ответ 4

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

Ответ 5

Еще один вариант, совместимый с 4.0:

Перед CayenneDataObject изменений вы можете восстановить новый объект CayenneDataObject из коллекции, связанной с контекстом, например:

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

затем получите доступ к ObjectId для каждого в коллекции, например:

ObjectId objectId = dataObject.getObjectId();

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

objectId.getIdSnapshot().values()

Ответ 6

Вот как я это сделал. Ты можешь попробовать

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

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

Ответ 7

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