#java #spring #entity-framework #hibernate #jpa
#java #весна #entity-framework #гибернация #jpa
Вопрос:
Я изучаю Hibernate (Spring) и сталкиваюсь со странной проблемой при удалении дочерних объектов из родительского.
Вот что у меня есть:
Родительский объект:
@Entity
public class Company {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "company_id", referencedColumnName = "id")
List<CompanyObject> companyObjects;
}
Дочерняя сущность:
@Entity
public class CompanyObject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@Enumerated(EnumType.STRING)
ObjectType type;
@ManyToOne
@JoinColumn(name = "company_id")
Company company;
}
Вот мои определения таблиц:
CREATE TABLE `company` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8
CREATE TABLE `company_object` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`company_id` bigint(20) NOT NULL,
`type` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK__company` (`company_id`),
CONSTRAINT `FK__company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
И, кроме того, у меня есть следующий update
метод:
// some code here
public void update(CompanyDto dto) {
Company company = repository.getCompanyById(companyId);
repository.save(dto.merge(company));
}
// some code here
public class CompanyDto {
private List<CompanyObjectDto> companyObjects = new ArrayList<>();
public Company merge(Company company) {
company.getCompanyObjects().clear();
for (CompanyObjectDto dto : companyObjects) {
company.getCompanyObjects().add(dto.to(company));
}
return company;
}
}
public class CompanyObjectDto {
ObjectType type;
public CompanyObject to(Company company) {
CompanyObject object = new CompanyObject();
object.setType(this.getType());
object.setCompany(company);
return object;
}
}
И как только я запускаю update
метод, я получаю следующую ошибку: java.sql.SQLWarning: Column 'company_id' cannot be null
. Я немного исследовал это и обнаружил, что если я закомментирую company.getCompanyObjects().clear();
строку, она работает нормально, поэтому, похоже, есть какая-то проблема с каскадным действием удаления объектов компании.
Может, пожалуйста, кто-нибудь указать мне на мои ошибки? Спасибо.
Комментарии:
1. При двунаправленном отображении должен быть только один @Joincolumn, и вам не хватает ‘mappedby’.
2. Проблема не в этом, но если вы не добавите
, orphanRemoval = true
к этойOneToMany
аннотации (где находится список), вы обнаружите, что она никогда не удаляет строки, которые вы удалили из списка. Отсутствие этого — это то, что вызовет у вас следующую проблему.3. @Kirinya, спасибо, это сработало. Не могли бы вы, пожалуйста, отправить свой ответ, чтобы я мог пометить его соответствующим образом?
Ответ №1:
Вы сопоставили свои объекты Company и CompanyObject двунаправленно, т. Е. Оба объекта имеют отношение к другому объекту.
В этом случае должен быть только один @Joincolumn, и один объект должен быть выбран в качестве объекта-владельца, а другой объект помечает отношение с помощью ‘mappedby’ (см. http://docs.oracle.com/javaee/6/api/javax/persistence/ManyToOne.html ).
Комментарии:
1. Еще раз спасибо!
Ответ №2:
Вы получаете сообщение об ошибке, потому что вы удаляете объекты из List
, а затем используете их List
в качестве ссылки на свой Company
объект. Смотрите приведенный ниже код :
private List<CompanyObjectDto> companyObjects = new ArrayList<>(); //Stmt 1
Приведенный выше код используется для определения списка, на который будет ссылаться приведенный ниже код :
company.getCompanyObjects().clear(); //It will clear out all objects
for (CompanyObjectDto dto : companyObjects) { //Iterating over empty list defined in stmt 1.
company.getCompanyObjects().add(dto.to(company));
}
Таким образом, ваш внешний ключ всегда будет иметь значение null, что недопустимо и вызывает исключение.
И ваш код работает, когда вы закомментируете List#clear
строку, потому что в этом сценарии в списке уже есть некоторые объекты, на которые ссылаются ссылки, которые не были изменены.
Комментарии:
1. Спасибо за ответ, но, к сожалению, не уверен, что понимаю. Вы хотите сказать, что мне нужно назначить
new ArrayList()
companyObjects
, чтобы заставить hibernate делать то, что я хочу?2. Ах, я думаю, я понял. На самом деле
companyObjects
не пусто. Некоторые данные поступают из веб-интерфейса.