Строка как идентификатор объекта, вставленный пользователем [EclipseLink]

[ВВЕДЕНИЕ]

  1. База данных: Апач Дерби
  2. JPA: EclipseLink

Эй, я искал ответ, но не смог его найти, так что вот оно. Я пишу простое приложение для судоку, и следующая функция, которую я хотел бы добавить, — это сохранение моих досок судоку в базе данных и извлечение их, когда это необходимо. Вот диаграмма UML двух моих основных классов: SudokuBoard.uml Структура двух моих сущности следующие:

Объект SudokuBoard:

@Entity
public class SudokuBoard implements Serializable, Cloneable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private static final long serialVersionUID = 1L;

@OneToMany(cascade=CascadeType.PERSIST)
private ArrayList<SudokuField> board;

public ArrayList<SudokuField> board() {
    return board;
}

public void setBoard(ArrayList<SudokuField> board) {
    this.board= board;
}

public Long etId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
} 

Объект SudokuField:

@Entity
public class SudokuField implements Serializable, Comparable<SudokuField>, 
Cloneable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Transient
private static final Logger logger = 
LoggerFactory.getLogger(SudokuField.class);
@Transient
private static final long serialVersionUID = 1L;

@Basic(fetch = FetchType.EAGER)
@Column(name = "Value")
private int value;

@ManyToOne
@JoinColumn(name = "board_fk", referencedColumnName = "id")
private SudokuBoard sudokuBoard;

Исполнение в DAO:

@Override
public void write(SudokuBoard obj, String path) throws 
FileNotFoundException, IOException {
    entityManager.getTransaction().begin();
    entityManager.persist(obj);
    entityManager.getTransaction().commit();
}

[ПРОБЛЕМА]

  1. Интересно, есть ли возможность не использовать автоматически сгенерированный ключ, а вместо этого использовать String как PK в объекте SudokuBoard. В моем приложении я реализовал привязку, поэтому я хотел бы сохранить один и тот же объект SudokuBoard, который со временем меняется под разными именами.

Надеюсь, я ясно изложил свои намерения. Спасибо за любую помощь и советы, как это можно сделать.


person sh1nen    schedule 27.05.2017    source источник


Ответы (1)


Использовать String в качестве первичного ключа просто — просто объявите его как таковой и удалите аннотацию @GeneratedValue.

Однако изменение первичного ключа (если это то, что вы подразумеваете под «сохранением одного и того же объекта (...) под разными именами») невозможно. Если вы попытаетесь persist/merge создать существующую сущность под другим первичным ключом, JPA либо вызовет исключение, либо обработает ее как новую сущность, что приведет к дублированию записей в базе данных. Проще говоря, присвоение идентификатора объекту является постоянным.

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

person crizzis    schedule 27.05.2017
comment
Под «сохранением одного и того же объекта (...) под разными именами» я имел в виду, что хотел бы иметь несколько записей одного и того же объекта, состояние которых меняется с течением времени. Также теперь, когда я создаю экземпляр объекта, я не могу сохранять его несколько раз, поскольку его PK назначается только один раз, и всякий раз, когда я пытаюсь это сделать, возникает исключение дублирующего ключа. Концепция, которую я хотел бы реализовать, такова: 1) Создать случайное поле судоку 2) Сохранить его в базе данных 3) Заполнить некоторые из отсутствующих полей той же доски 4) Иметь возможность снова сохранить его под другим идентификатором - person sh1nen; 27.05.2017
comment
Хорошо, теперь я понял. К сожалению, я не думаю, что есть простой способ реализовать то, что вы хотите, кроме как вручную создать и сохранить копию SudokuBoard и SudokuFields. Вам не кажется, что ваша модель данных слишком сложна? Нужна ли SudokuField собственная постоянная идентичность? Я бы предложил использовать целочисленный список. Если вам абсолютно необходима отдельная модель SudokuField, я бы все равно заменил сопоставление @OneToMany на @ElementCollection из @Embeddables. - person crizzis; 27.05.2017
comment
Таким образом, вместо того, чтобы копировать всю структуру вручную, вы сможете detach Sudokuboard обновить первичный ключ и persist как новый объект. Предоставление новых копий для списка SudokuField больше не потребуется. - person crizzis; 27.05.2017
comment
при этом я смогу хранить несколько досок в базе данных или только самую актуальную? Постараюсь это реализовать. Спасибо за поддержку и краткое объяснение - person sh1nen; 27.05.2017
comment
Как правило, вы merge отсоединяете объект, сохраняя при этом исходный идентификатор, чтобы «показать» менеджеру объектов, какое состояние вы ожидаете от него теперь. Однако, если вы измените идентификатор, а затем persist вместо этого отсоедините объект, он будет рассматриваться как совершенно новый. Эта операция никак не повлияет на исходную сущность, поэтому вы получите две сущности вместо одной. - person crizzis; 27.05.2017