Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > JPA: Автогенерация ID объекта?


Автор: Andrey1 28.4.2008, 16:05
Что нужно изменить/добавить, чтобы автогенерировались id для новых элементов при сохранении нового объекта object:

Код

...
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("MyPU");
        em = factory.createEntityManager();

        em.getTransaction().begin();
        BigDecimal id = null;

            em.persist(object);
            em.getTransaction().commit();
            id = object.getObjectId();
...



id в entity классе для object:
 
Код

   @Id
    @Column(name = "OBJECT_ID", nullable = false)
    private BigDecimal objectId;


База - Оракл.

Автор: Zamuta 28.4.2008, 16:30
Andrey1
Цитата

Applications can choose one of four different id generation strategies by specifying a strat-
egy in the 
strategy element. The value may be any one of AUTO, TABLE, SEQUENCE, or IDENTITY 
enumerated values of the 
GenerationType enumerated type.
Table and sequence generators may be specifically defined and then reused by multiple 
entity classes. These generators are named and are globally accessible to all of the entities in 
the persistence unit.

Не знаю, что поддерживает оракл, но это должно работать. 
Код

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name = "OBJECT_ID", nullable = false)
    private BigDecimal objectId;

Автор: Andrey1 28.4.2008, 16:55
Спасибо. Тоже думал, что это должно работать, однако - не работает...  smile 
Код

[TopLink Warning]: 2008.04.28 05:45:32.395--ClientSession(22736215)--Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-00942: table or view does not exist

Error Code: 942
Call: UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
        bind => [50, SEQ_GEN]
Query: DataModifyQuery()



Если заменить на @GeneratedValue(strategy=GenerationType.IDENTITY), то результат тот же, но ошибка другая:
Код


[TopLink Warning]: 2008.04.28 05:49:13.362--ClientSession(11228395)--Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-02289: sequence does not exist

Error Code: 2289
Call: SELECT SEQ_GEN_SEQUENCE.NEXTVAL FROM DUAL
Query: ValueReadQuery()



Здесь http://java.sun.com/developer/technicalArticles/J2SE/Desktop/persistenceapi/ еще пишут, что можно писать аля:

Код

/**
     * Gets the id of this Player. The persistence provider should 
     * autogenerate a unique id for new player objects.
     * @return the id
     */
    @Id
    @GeneratedValue
    public Long getId() {
        return this.id;
    }

, но разницы нет.

Автор: medi 28.4.2008, 18:22
не знаю как TopLink, но в hibernate

@GeneratedValue(strategy=GenerationType.IDENTITY)

говорит о том, чтоб при генерации id использовать механизмы базы данных.
Для этого испильзуется sequence, которые есть в базе для каждой таблици(с PrimaryKey (AUTO_GEN))
 
У тебя, TopLink запрашивает этото, но видемо не находит. 
Call: SELECT SEQ_GEN_SEQUENCE.NEXTVAL

Проверь как называется имя sequence в базе, или может там вообще нету секуэнса для ID 

Автор: Andrey1 28.4.2008, 22:45
Цитата(medi @  28.4.2008,  18:22 Найти цитируемый пост)
Проверь как называется имя sequence в базе, или может там вообще нету секуэнса для ID

Я его ручками не вызывал... 

Автор: medi 28.4.2008, 22:58
Что ты ручками не вызывал?

Автор: Andrey1 28.4.2008, 23:12
Цитата(medi @  28.4.2008,  22:58 Найти цитируемый пост)
Что ты ручками не вызывал? 

Запрос руками не писал.

Автор: medi 28.4.2008, 23:20
я не говорю, что ты его писал, это делает O/R-mapper.
У тебя в таблице поле OBJECT_ID как PrimaryKey?

Добавлено через 2 минуты и 51 секунду
я пишу "называется", а ты наверно вызывается прочитал?
будь внимателен smile

Автор: Ivan Kolesnikov 29.4.2008, 06:13
Фактически у нас имеется 3 метода получения id: TABLE, SEQUENCE, or IDENTITY и еще AUTO - который как я понимаю выбирает подходящую реализацию в зависимости от базы, в данном случае, судя по ошибке, была выбрана TABLE.
Что конкретный метод обозначает:
TABLE - должна быть таблица по умолчанию с именем SEQUENCE и двумя полями SEQ_COUNT и SEQ_NAME, соответственно следующее значение ID и идентификатор генератора (не помню какой значение), имя таблицы и имена полей можно настроить. Как я понимаю этот метод удобно использовать в СУБД в которых нет SEQUENCE.
SEQUENCE - для генерацию используется SEQUENCE, в данном случае с именем SEQ_GEN_SEQUENCE, опять же имя можно настроить, как я понимаю для Oracle этот способ больше подходит, только нужно указать правильное имя SEQUENCE из которого брать этот ID.
IDENTITY - данный метод на сколько я знаю не поддерживается в Oracle и используется вместо него SEQUENCE, суть его заключается в том, что некоторые СУБД например MySQL позволяют получить после выполнения запроса значения идентификатора установленного в поле id, типа кажется auto_increment.

Что выбрать в данном случае. Если для генерации ID используется SEQUENCE, а так скорее всего и есть, то нужно выбирать этот метод, но тут есть один момент: часто id проставляется в триггере из сиквенса автоматом, в данном случае это приведет к ошибке, так как будет будет добавлена запись не с тем id что передали. Необходимо изменить триггер, чтобы если id уже заполнено, то не изменять его.

Установить нужно имя сиквенса можно следующим образом
Код

@Id
@SequenceGenerator(name="seq_name", sequenceName="seq_name_in_db")
@GeneratedValue(generator="seq_name")
private Integer id;

Автор: medi 29.4.2008, 06:27
Хорошая инфа, спасибо...

Автор: Andrey1 29.4.2008, 10:32
Спасибо.

Пришлось создать табличку SEQUENCE c столбцами: SEQ_COUNT, SEQ_NAME, и внести в нее: 1, SEQ_GEN.

Странно, почему topLink не догадался это сделать, если она ему так нужна...

Автор: Ivan Kolesnikov 29.4.2008, 13:34
Цитата

Странно, почему topLink не догадался это сделать, если она ему так нужна... 

Про topLink не знаю, с ним не работал, я использую реализацию hibernate, там можно через свойства указать нужно ли создавать или обновлять объекты, по умолчанию они не создаются.

Автор: EJack 29.4.2008, 17:57
Можно посмотреть здест:
http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)