Hibernate:仅将 ManyToOne 映射到具有特定列值的外键实体
Hibernate: Mapping ManyToOne only to foreign key entities with particular column value
我觉得这有点奇怪,我不确定这是否可能,但我的要求如下:
我有两个实体:Dataset
和 Organization
。 Dataset
实体具有到 Organization
实体的多对一映射。组织有两种类型:Customer
和 Partner
。业务需求是只有 Partner
类型的组织可以有数据集。那么,有没有什么方法可以将 Dataset
实体映射到 Organization
,使得 Dataset
中的所有外键仅包含类型为 [=17= 的 Organization
实体的 ID ]?
组织实体定义如下:
@Entity
@Table(name = "organization")
public class Organization {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String type;
private String name;
private String address;
private String status;
private String subtype;
@Column(name = "created_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date createdDate;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "organization_id", insertable = false, updatable = false)
private List<User> users;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({ @JoinColumn(name = "subtype", referencedColumnName = "name", insertable = false, updatable = false),
@JoinColumn(name = "type", referencedColumnName = "organization_type", insertable = false, updatable = false) })
private OrganizationSubType organizationSubType;
// Getters and setters
.
.
.
此处,type
列将包含 PARTNER
或 CUSTOMER
。
这是我目前正在设计的数据集实体:
@Entity
@Table(name="datasets")
public class Dataset {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name="partner_id", nullable = false)
private long partnerId;
@Column(nullable = false, unique = true)
private String name;
private String description;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private DatasetStatus datasetStatus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="partner_id", referencedColumnName="id", insertable = false, updatable = false)
private Organization partner;
//Getters and setters
那么,有什么方法可以对映射设置约束,使得在持久化新数据集实体时,组织 ID 始终属于类型为合作伙伴而非客户的实体?或者我是否必须将客户和合作伙伴组织作为单独的实体分开?
有几个选项可以实现它:
通过在持久化之前构建新的 Dataset
对象时在业务层添加验证。此类验证将检查给定 Organisation
是否可以与基于组织类型创建的 Dataset
实体相关联。
通过使用 Bean 验证 API 并定义自定义约束验证器。实体上的每次更改都会调用此类验证器。
将hibernate-validator 添加到类路径
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.4.Final</version>
</dependency>
为新验证定义注解
@Constraint(validatedBy = PartnerOrganisationValidator.class)
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface PartnerOrganisation {
String message() default "Organisation should be of type PARTNER";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
定义约束验证器
public class PartnerOrganisationValidator implements ContraintValidator<PartnerOrganisation, Organisation> {
@Override
public boolean isValid(Organisation organisation, ConstraintValidatorContext constraintValidatorContext) {
return organisation == null || "PARTNER".equals(organisation.type);
}
}
通过将验证器的完全限定名称添加到 META-INF/services/javax.validation.ConstraintValidator
文件,在休眠验证器中注册验证器。
最后一步是在您的实体中使用验证器:
@PartnerOrganisation
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="partner_id", referencedColumnName="id", insertable = false, updatable = false)
private Organization partner;
如果您使用的数据库支持它,则使用 SQL CHECK CONSTRAINT
- 就像
中的示例一样
通过将合作伙伴组织和客户组织建模为单独的实体 类。
由于合作伙伴和客户的组织结构与选项 4 中的方法相同。对于这种情况似乎过于复杂。我建议选择选项 1。
我觉得这有点奇怪,我不确定这是否可能,但我的要求如下:
我有两个实体:Dataset
和 Organization
。 Dataset
实体具有到 Organization
实体的多对一映射。组织有两种类型:Customer
和 Partner
。业务需求是只有 Partner
类型的组织可以有数据集。那么,有没有什么方法可以将 Dataset
实体映射到 Organization
,使得 Dataset
中的所有外键仅包含类型为 [=17= 的 Organization
实体的 ID ]?
组织实体定义如下:
@Entity
@Table(name = "organization")
public class Organization {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String type;
private String name;
private String address;
private String status;
private String subtype;
@Column(name = "created_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date createdDate;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "organization_id", insertable = false, updatable = false)
private List<User> users;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({ @JoinColumn(name = "subtype", referencedColumnName = "name", insertable = false, updatable = false),
@JoinColumn(name = "type", referencedColumnName = "organization_type", insertable = false, updatable = false) })
private OrganizationSubType organizationSubType;
// Getters and setters
.
.
.
此处,type
列将包含 PARTNER
或 CUSTOMER
。
这是我目前正在设计的数据集实体:
@Entity
@Table(name="datasets")
public class Dataset {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name="partner_id", nullable = false)
private long partnerId;
@Column(nullable = false, unique = true)
private String name;
private String description;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private DatasetStatus datasetStatus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="partner_id", referencedColumnName="id", insertable = false, updatable = false)
private Organization partner;
//Getters and setters
那么,有什么方法可以对映射设置约束,使得在持久化新数据集实体时,组织 ID 始终属于类型为合作伙伴而非客户的实体?或者我是否必须将客户和合作伙伴组织作为单独的实体分开?
有几个选项可以实现它:
通过在持久化之前构建新的
Dataset
对象时在业务层添加验证。此类验证将检查给定Organisation
是否可以与基于组织类型创建的Dataset
实体相关联。通过使用 Bean 验证 API 并定义自定义约束验证器。实体上的每次更改都会调用此类验证器。
将hibernate-validator 添加到类路径
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.4.Final</version>
</dependency>
为新验证定义注解
@Constraint(validatedBy = PartnerOrganisationValidator.class)
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface PartnerOrganisation {
String message() default "Organisation should be of type PARTNER";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
定义约束验证器
public class PartnerOrganisationValidator implements ContraintValidator<PartnerOrganisation, Organisation> {
@Override
public boolean isValid(Organisation organisation, ConstraintValidatorContext constraintValidatorContext) {
return organisation == null || "PARTNER".equals(organisation.type);
}
}
通过将验证器的完全限定名称添加到 META-INF/services/javax.validation.ConstraintValidator
文件,在休眠验证器中注册验证器。
最后一步是在您的实体中使用验证器:
@PartnerOrganisation
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="partner_id", referencedColumnName="id", insertable = false, updatable = false)
private Organization partner;
如果您使用的数据库支持它,则使用
中的示例一样SQL CHECK CONSTRAINT
- 就像通过将合作伙伴组织和客户组织建模为单独的实体 类。
由于合作伙伴和客户的组织结构与选项 4 中的方法相同。对于这种情况似乎过于复杂。我建议选择选项 1。