Hibernate JPA Sequence (без идентификатора) - PullRequest
114 голосов
/ 10 ноября 2008

Можно ли использовать последовательность БД для некоторого столбца, который не является идентификатором / не является частью составного идентификатора ?

Я использую hibernate в качестве провайдера jpa, и у меня есть таблица, в которой есть несколько столбцов, которые генерируют значения (используя последовательность), хотя они не являются частью идентификатора.

Я хочу использовать последовательность для создания нового значения для сущности, где столбец для последовательности - НЕ (часть) первичного ключа:

@Entity
@Table(name = "MyTable")
public class MyEntity {

    //...
    @Id //... etc
    public Long getId() {
        return id;
    }

   //note NO @Id here! but this doesn't work...
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "myGen")
    @SequenceGenerator(name = "myGen", sequenceName = "MY_SEQUENCE")
    @Column(name = "SEQ_VAL", unique = false, nullable = false, insertable = true, updatable = true)
    public Long getMySequencedValue(){
      return myVal;
    }

}

Тогда, когда я сделаю это:

em.persist(new MyEntity());

идентификатор будет сгенерирован, но свойство mySequenceVal также будет сгенерировано моим JPA-провайдером.

Просто чтобы прояснить ситуацию: я хочу, чтобы Hibernate генерировал значение для свойства mySequencedValue. Я знаю, что Hibernate может обрабатывать значения, сгенерированные базой данных, но я не хочу использовать триггер или любую другую вещь, кроме самого Hibernate, для генерации значения для моего свойства. Если Hibernate может генерировать значения для первичных ключей, почему он не может генерировать для простого свойства?

Ответы [ 15 ]

0 голосов
/ 07 мая 2019

Похоже, что поток старый, я просто хотел добавить свое решение здесь (используя AspectJ - AOP весной).

Решение заключается в создании пользовательской аннотации @InjectSequenceValue следующим образом.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectSequenceValue {
    String sequencename();
}

Теперь вы можете аннотировать любое поле в сущности, так что значение базового поля (Long / Integer) будет введено во время выполнения с использованием следующего значения последовательности.

Аннотировать, как это.

//serialNumber will be injected dynamically, with the next value of the serialnum_sequence.
 @InjectSequenceValue(sequencename = "serialnum_sequence") 
  Long serialNumber;

Пока что мы пометили поле, в которое нам нужно ввести значение последовательности. Итак, мы посмотрим, как ввести значение последовательности в отмеченные поля, это делается путем создания среза точки в AspectJ.

Мы запустим инъекцию непосредственно перед выполнением метода save/persist. Это делается в следующем классе.

@Aspect
@Configuration
public class AspectDefinition {

    @Autowired
    JdbcTemplate jdbcTemplate;


    //@Before("execution(* org.hibernate.session.save(..))") Use this for Hibernate.(also include session.save())
    @Before("execution(* org.springframework.data.repository.CrudRepository.save(..))") //This is for JPA.
    public void generateSequence(JoinPoint joinPoint){

        Object [] aragumentList=joinPoint.getArgs(); //Getting all arguments of the save
        for (Object arg :aragumentList ) {
            if (arg.getClass().isAnnotationPresent(Entity.class)){ // getting the Entity class

                Field[] fields = arg.getClass().getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(InjectSequenceValue.class)) { //getting annotated fields

                        field.setAccessible(true); 
                        try {
                            if (field.get(arg) == null){ // Setting the next value
                                String sequenceName=field.getAnnotation(InjectSequenceValue.class).sequencename();
                                long nextval=getNextValue(sequenceName);
                                System.out.println("Next value :"+nextval); //TODO remove sout.
                                field.set(arg, nextval);
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }
    }

    /**
     * This method fetches the next value from sequence
     * @param sequence
     * @return
     */

    public long getNextValue(String sequence){
        long sequenceNextVal=0L;

        SqlRowSet sqlRowSet= jdbcTemplate.queryForRowSet("SELECT "+sequence+".NEXTVAL as value FROM DUAL");
        while (sqlRowSet.next()){
            sequenceNextVal=sqlRowSet.getLong("value");

        }
        return  sequenceNextVal;
    }
}

Теперь вы можете комментировать любую сущность, как показано ниже.

@Entity
@Table(name = "T_USER")
public class UserEntity {

    @Id
    @SequenceGenerator(sequenceName = "userid_sequence",name = "this_seq")
    @GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "this_seq")
    Long id;
    String userName;
    String password;

    @InjectSequenceValue(sequencename = "serialnum_sequence") // this will be injected at the time of saving.
    Long serialNumber;

    String name;
}
0 голосов
/ 19 марта 2018

После нескольких часов это помогло мне решить мою проблему:

Для Oracle 12c:

ID NUMBER GENERATED as IDENTITY

Для H2:

ID BIGINT GENERATED as auto_increment

Также сделайте:

@Column(insertable = false)
0 голосов
/ 11 ноября 2009

Это не то же самое, что использование последовательности. При использовании последовательности вы ничего не вставляете и не обновляете. Вы просто получаете следующее значение последовательности. Похоже, что Hibernate не поддерживает его.

0 голосов
/ 17 ноября 2008

"Я не хочу использовать триггер или что-то другое, кроме самого Hibernate, для генерации значения для моего свойства"

В таком случае, как насчет создания реализации UserType, которая генерирует требуемое значение, и настройки метаданных для использования этого UserType для сохранения свойства mySequenceVal?

0 голосов
/ 12 ноября 2008

Я был в такой ситуации, как вы (последовательность JPA / Hibernate для поля, отличного от @Id), и я закончил тем, что создал в моей схеме базы данных триггер, который добавляет уникальный порядковый номер при вставке. Я просто никогда не работал с JPA / Hibernate

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...