Я пытаюсь найти способ управления составным идентификатором таблицы, которая содержит автоматически сгенерированное значение и внешний ключ.Но использование @IdClass
или @EmbeddedId
не работает.В обоих случаях у меня есть исключение при попытке вставить объект в базу данных.
Я создал пример проекта , чтобы продемонстрировать свою проблему.Этот проект основан на шаблонах тестовых примеров Hibernate .
Общая часть:
Сущность Agent
, с которой должны быть связаны все Mission
.
@Getter
@Setter
@Entity
public class Agent implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private String login;
private String lastName;
private String firstName;
}
@IdClass
case:
ID для объекта @IdClass
:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class IdClassTypeMissionId implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String agent;
}
Mission
с использованием аннотации @IdClass
:
@Getter
@Setter
@Entity
@IdClass(IdClassTypeMissionId.class)
public class IdClassTypeMission implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Id
@ManyToOne(optional = false)
@JoinColumn(name = "agent_login", referencedColumnName = "login", foreignKey = @ForeignKey(name = "fk_id_class_type_mission_agent"))
private Agent agent;
private LocalDateTime dateEnd;
private LocalDateTime dateStart;
private String city;
}
контрольный пример :
@Test
public void idClassTypeMissionTest() throws Exception {
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
final Agent agent = new Agent();
agent.setLogin("jdoe");
agent.setFirstName("John");
agent.setLastName("Doe");
entityManager.persist(agent);
entityManager.flush();
entityManager.refresh(agent);
final IdClassTypeMission mission = new IdClassTypeMission();
mission.setCity("New York");
mission.setDateStart(LocalDateTime.of(2018, 12, 5, 7, 30));
mission.setDateEnd(LocalDateTime.of(2018, 12, 6, 18, 30));
mission.setAgent(agent);
entityManager.persist(mission); // <- It fails here.
entityManager.flush();
entityManager.refresh(mission);
final IdClassTypeMission result = entityManager.find(IdClassTypeMission.class, new IdClassTypeMissionId(mission.getId(), "jdoe"));
assertNotNull(result);
assertNotNull(result.getId());
assertNotNull(result.getAgent());
assertEquals("jdoe", result.getAgent().getLogin());
assertEquals("New York", result.getCity());
entityManager.getTransaction().commit();
entityManager.close();
}
Я получаю следующее исключение:
Caused by: org.hibernate.HibernateException: No part of a composite identifier may be null
@EmbeddedId
case:
Часть @Embedded
:
@Data
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
public class EmbeddedTypeMissionId implements Serializable {
private static final long serialVersionUID = 1L;
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String agentLogin;
}
Объект Mission
:
@Getter
@Setter
@Entity
public class EmbeddedTypeMission implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private EmbeddedTypeMissionId id;
@MapsId("agentLogin")
@ManyToOne(optional = false)
@JoinColumn(name = "agent_login", referencedColumnName = "login", foreignKey = @ForeignKey(name = "fk_embedded_type_mission_agent"))
private Agent agent;
private LocalDateTime dateEnd;
private LocalDateTime dateStart;
private String city;
}
Контрольный пример :
@Test
public void embeddedIdTypeMissionTest() throws Exception {
final EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
final Agent agent = new Agent();
agent.setLogin("jdoe");
agent.setFirstName("John");
agent.setLastName("Doe");
entityManager.persist(agent);
entityManager.flush();
entityManager.refresh(agent);
final EmbeddedTypeMission mission = new EmbeddedTypeMission();
mission.setCity("New York");
mission.setDateStart(LocalDateTime.of(2018, 12, 5, 7, 30));
mission.setDateEnd(LocalDateTime.of(2018, 12, 6, 18, 30));
mission.setAgent(agent);
entityManager.persist(mission);
entityManager.flush(); // <- It fails here.
entityManager.refresh(mission);
final EmbeddedTypeMission result = entityManager.find(EmbeddedTypeMission.class, new EmbeddedTypeMissionId(mission.getId().getId(), "jdoe"));
assertNotNull(result);
assertNotNull(result.getId());
assertNotNull(result.getId().getId());
assertEquals("jdoe", result.getId().getAgent());
assertEquals("New York", result.getCity());
entityManager.getTransaction().commit();
entityManager.close();
}
Я получаю следующее исключение:
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "ID"; SQL statement:
insert into EmbeddedTypeMission (city, dateEnd, dateStart, agent_login, id) values (?, ?, ?, ?, ?) [23502-176]
Анализ
В случае @IdClass
мне удалось найти билет с ошибкой в Hibernate .Вот почему я пытался использовать @EmbeddedId
.
Сначала я подумал, что это работает: сохранение объекта с использованием метода save
из @Repository
, похоже, работает.Но при попытке вставить сущность с помощью EntityManager
не получилось ...
Я что-то пропустил?Это проблема в моих тестах?Любое предложение, чтобы заставить его работать?