Я хочу, чтобы у продукта был необязательный ProductType. Но во время генерации схемы Hibernate по какой-то причине игнорирует мое определение и создает столбец, не допускающий значения NULL, для внешнего ключа. Мы используем Hibernate для управления схемой и SQL Server 16.
Вот что Hibernate выводит из системы во время создания схемы:
Hibernate: drop table if exists my_product
Hibernate: drop table if exists my_producttype
create table my_product (id uniqueidentifier not null, name varchar(255) not null, typeId uniqueidentifier not null, primary key (id))
create table my_producttype (id uniqueidentifier not null, name varchar(255) not null, primary key (id))
alter table pg_product add constraint FK123456789 foreign key (typeId) references my_producttype
Это схема, определенная в Java:
@Entity
@Table(name = "my_product")
public class Product extends CoreModel<Product> {
@NotNull
private String name;
@ManyToOne(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
@JoinColumn(name = "typeId", nullable = true)
@JsonIgnore
@org.springframework.lang.Nullable
private ProductType productType;
}
и этот абстрактный класс модели
@MappedSuperclass
public abstract class CoreModel<T extends CoreModel<T>> {
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Column(updatable = false)
@GeneratedValue(strategy = GenerationType.UUID)
@Id
private UUID id;
}
и, наконец, указанный объект
@Entity
@Table(name = "my_producttype")
public class ProductType extends CoreModel<ProductType> {
@NotNull
private String name;
}
соответствующий application.yml
spring:
datasource:
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
jpa:
database: sql_server
open-in-view: false
hibernate:
ddl-auto: create
naming:
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
properties:
hibernate:
dialect: org.hibernate.dialect.SQLServerDialect
jdbc:
time_zone: UTC
Что я пробовал:
Системная информация
Виновник найден, и я должен извиниться, так как вы не смогли этого понять.
Свойство productType
является частным и поэтому имеет геттеры и сеттеры, которые я пропустил. Важно отметить, что во время рефакторинга я забыл удалить там аннотацию @NotNull - и сегодня я узнал, что Spring/Hibernate также анализирует их во время генерации схемы, а не только аннотации полей.
Исправление должно было измениться:
public @NotNull ProductType getProductType() {
return productType;
}
public void setProductType(@NotNull ProductType productType) {
this.productType = productType;
}
к этому
public ProductType getProductType() {
return productType;
}
public void setProductType(ProductType productType) {
this.productType = productType;
}
Извините, но спасибо, что были моей резиновой уткой.
@JohnWilliams внешний ключ может быть совершенно нулевым, SQL не запрещает это (ссылка может быть необязательной). Таким образом, вам не нужны фиктивные отношения в вашей базе данных.