Я делаю практический проект с помощью Spring MVC и Hibernate. Зная, что Hibernate может использовать аннотацию для сопоставления строки db с объектом, я пытаюсь использовать Query, чтобы получить весь объект Account из db в список, в то время как при их вставке у них есть дублированный идентификатор.
Код для получения аккаунтов
@Override
public List<Account> getAccounts() {
List<Account> list = new ArrayList<>();
try {
Session session = sessionFactory.getCurrentSession();
Query<AccountEntity> query = session.createQuery("From AccountEntity", AccountEntity.class);
List<AccountEntity> accounts = query.getResultList();
for (int i = 0; i < accounts.size(); i++) {
AccountEntity accountEntity = (AccountEntity) accounts.get(i);
Account account = new Account();
account.setAccountNo(accountEntity.getAccNo());
account.setAccountHolderName(accountEntity.getAccHolderName());
account.setBalance(accountEntity.getBalance());
account.setAccountType(accountEntity.getAccountType());
account.setPsCode(accountEntity.getPsCode());
account.setDateOfBirth(accountEntity.getDateOfBirth());
System.out.println("#: " + account.getAccountNo() + ", name: " + account.getAccountHolderName());
list.add(account);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return list;
}
Теперь, когда я использую их в представлениях, дублированные идентификаторы создают строки с одинаковым идентификатором, именем и балансом (имена не совпадают в базе данных) .строки становятся одинаковыми
Это потому, что отображение в Hibernate полагается просто на идентификатор, если идентификатор тот же, он создает тот же объект.
AccountEntity с аннотациями:
@Юридическое лицо @Table (name = "account") public class AccountEntity {
@Id
@Column(name = "accountNo")
private int accNo;
@Column(name = "accountHolderName")
private String accHolderName;
@Column(name = "balance")
private int balance;
@Column(name = "accountType")
private String accountType;
@Column(name = "dateOfBirth")
private Date dateOfBirth;
@Column(name = "psCode")
private String psCode;
public AccountEntity() {
}
public int getAccNo() {
return accNo;
}
public void setAccNo(int accNo) {
this.accNo = accNo;
}
public String getAccHolderName() {
return accHolderName;
}
public void setAccHolderName(String accHolderName) {
this.accHolderName = accHolderName;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public String getPsCode() {
return psCode;
}
public void setPsCode(String psCode) {
this.psCode = psCode;
}
} Что, если я удалю здесь @Id?




Аннотация @Id объявляет поле первичного ключа в сущности. У каждой сущности в спящем режиме должен быть первичный ключ. Почему у вас есть повторяющиеся записи в вашей таблице, если accountNo является столбцом первичного ключа в базе данных. Если в таблице нет столбца первичного ключа, рассмотрите возможность наличия столбца псевдо-первичного ключа.
Вам понадобится первичный ключ для выполнения любых операций CRUD с сущностью. Вы можете не отображать первичный ключ для пользователя. Для большинства реляционных баз данных вы можете установить первичный ключ, который будет автоматически сгенерирован базой данных. Например, следующий код заставит спящий режим полагаться на базу данных для генерации столбца id.
@Id
@GeneratedValue
@Column(name = "ItemId", unique = true, nullable = false)
private Integer Id;
Например, в SQL Server вы можете определить столбец как: [ItemId] [int] IDENTITY (10000000,1) NOT NULL,
Hibernate кэширует объекты по идентификатору в своем кэше первого уровня (сеанс Hibernate). Как только он находит объект для идентификатора и кэширует его, он всегда возвращает один и тот же экземпляр объекта в течение всего сеанса Hibernate. (Это случай шаблона, называемого «карта идентичности», есть хорошее объяснение, данное здесь).
@Id отмечает поле, сопоставленное с первичным ключом таблицы, сопоставленной с классом сущности. Значения первичных ключей должны быть уникальными, две строки таблицы не могут иметь одинаковое значение Id. Hibernate ожидает, что вы будете сопоставляться с какой-то реляционной моделью, а не с любым случайным мусором, а это означает, что ключи должны быть уникальными.
Кстати, имейте в виду, что вы не должны перехватывать исключения, как показано в опубликованном вами коде, просто позвольте им быть выброшенными. Вы можете указать компонент, помеченный @ControllerAdvice, для обработки исключений, генерируемых контроллером. Самый простой и понятный подход - использовать уровень транзакционного сервиса отдельно от контроллеров для бизнес-логики и доступа к данным.
спасибо за объяснение, довольно солидно. Вы знаете, где я могу найти соответствующую документацию?
@Zhen Xu: начните с hibernate.org/orm/documentation/, книга Бауэра и Кинга тоже хороша.
Я сделал это, когда тестировал. Я не добавлял первичный ключ с автоинкрементом, вместо этого первичный ключ был вставлен из формы из внешнего интерфейса. Как это сделать? Просто установить автоинкремент первичного ключа? Это немного странно, поскольку вы создаете объект, и его идентификатор должен быть указан, но на самом деле вы не получаете никаких параметров из формы, чтобы указать это. Как присвоить этому объекту идентификатор?