Невозможно установить идентификатор поля java.lang.Integer в org.hibernate.id.IdentifierGeneratorHelper

Мне нужно сохранить некоторые данные в базе данных MySQL, используя Jpa 2/Hibernate 3.5.1. По устаревшим причинам таблица, в которой я хочу хранить данные, имеет составной первичный ключ. Первая часть первичного ключа имеет тип INTEGER (автоинкрементное значение), вторая часть имеет тип BIGINT (длинный в Java-коде — задается вручную перед сохранением).

Я реализовал (пример кода под трассировкой стека) комбинированный первичный ключ через аннотацию @IdClass, часть первого ключа также имеет набор стратегий генерации: @GeneratedValue(strategy = GenerationType.IDENTITY)

При попытке сохранить объект с таким кодом

...
TestData testData = new TestData("data");
testData.setIdPartTwo(2L);

entityManager.getTransaction().begin();
entityManager.persist(testData);
entityManager.getTransaction().commit();

выдается следующее исключение:

javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of org.example.persistence.TestDataId.idPartOne
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1174)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:674)
at org.example.persistence.PersistenceTest.shouldPersistTestData(PersistenceTest.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:640)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:627)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:799)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1103)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:137)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:121)
at org.testng.TestRunner.runWorkers(TestRunner.java:1098)
at org.testng.TestRunner.privateRun(TestRunner.java:727)
at org.testng.TestRunner.run(TestRunner.java:581)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:315)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:310)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:272)
at org.testng.SuiteRunner.run(SuiteRunner.java:221)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:40)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:83)
at org.testng.internal.thread.ThreadUtil$CountDownLatchedRunnable.run(ThreadUtil.java:151)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)


Caused by: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of org.example.persistence.TestDataId.idPartOne
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:151)
at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:438)
at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:122)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:800)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:774)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:778)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:668)
... 24 more


Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Integer field org.example.persistence.TestDataId.idPartOne to org.hibernate.id.IdentifierGeneratorHelper$2
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:139)
... 35 more

Мой класс сущности выглядит так:

@Entity
@IdClass(TestDataId.class)
public class TestData implements Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer idPartOne;
  @Id
  private Long idPartTwo;
  private String data;
  public TestData() {}
    // getters and setters
    // hashCode() and equals()
}

Комбинированный первичный ключ:

public class TestDataId implements Serializable {

  private static final long serialVersionUID = 1L;
  private Integer idPartOne;
  private Long idPartTwo;
  public TestDataId() {}
    // getters and setters
    // hashCode() and equals()
}

Тестовая таблица была создана со следующим утверждением:

CREATE TABLE `testdb`.`testdata` 
(`idPartOne` INTEGER NOT NULL AUTO_INCREMENT,
 `idPartTwo` BIGINT(20) NOT NULL DEFAULT 0,
 `data` VARCHAR(45),
 PRIMARY KEY(`idPartOne`, `idPartTwo`))
ENGINE = InnoDB;

Изменение GenerationType на TABLE заставит его работать, но будет генерировать значения idPartOne с шагом ~ 32 000. К сожалению, другое приложение использует ту же самую таблицу базы данных без JPA/Hibernate и хорошо увеличивает эту часть идентификатора с шагом 1.

Требуется, чтобы генерация идентификатора выполнялась одинаково, независимо от того, какое приложение хранит данные в этой таблице (то есть приращение идентификатора на 1). Что было бы лучшим решением для достижения этого? Подсказка, мы не можем изменить другое приложение!

Любая помощь очень ценится.

Спасибо,

Маркус


person user506600    schedule 13.11.2010    source источник
comment
«idParOne» автоматически увеличивается, почему вы определяете PK таблицы как PRIMARY KEY (idPartOne, idPartTwo)? Возможно ли, что в эту таблицу вставлена ​​запись, но с дублированным «idPartOne»?   -  person Mike Lue    schedule 07.03.2012


Ответы (1)


Это работает, когда вы аннотируете встроенный идентификатор?

@Embeddable
public class TestDataId
{
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Integer idPartOne;
    private Long idPartTwo;
}

@Entity
public class TestData
{
    @EmbeddedId
    private TestDataId key;
    private String data;
}
person siebz0r    schedule 07.06.2012
comment
У меня такая же проблема, EmbeddedId не работает и выдает следующее исключение: com.microsoft.sqlserver.jdbc.SQLServerException: Ein expliziter Wert für die Identitätsspalte kann nicht in der ZIFCARGOSOFT_INVOICE_ITEMS-Tabelle eingefügt werden, wenn IDENTITY_INSERT auf OFF festgelegt ist. см. полное исключение: gist.github.com/stefanwendelmann/ - person Stefan Höltker; 16.12.2019