Java 休眠检查删除约束
我使用Spring-Hibernate来控制应用程序中的模型。这些模型相互链接(一对多、多对多、几乎各种类型的关系),现在我在删除一个被其他实体使用的实体时遇到了一个问题。问题是,我想显示详细信息,确切地告知其他哪些对象(类型、名称)正在使用我要删除的实体。Hibernate带给我的不是关于约束冲突的常见消息。Java 休眠检查删除约束,java,spring,hibernate,spring-mvc,constraints,Java,Spring,Hibernate,Spring Mvc,Constraints,我使用Spring-Hibernate来控制应用程序中的模型。这些模型相互链接(一对多、多对多、几乎各种类型的关系),现在我在删除一个被其他实体使用的实体时遇到了一个问题。问题是,我想显示详细信息,确切地告知其他哪些对象(类型、名称)正在使用我要删除的实体。Hibernate带给我的不是关于约束冲突的常见消息。 例如:汽车-->人,房子-->人;然后,当我删除一个拥有汽车和房子的人时,消息将显示“有汽车(名为福特野马)和房子(名为MyHouse)与此人链接”。 1.那么,Hibernate中是否
例如:
汽车-->人,房子-->人
;然后,当我删除一个拥有汽车和房子的人时,消息将显示“有汽车(名为福特野马)和房子(名为MyHouse)与此人链接”。1.那么,Hibernate中是否有任何方法支持此需求?我想这个特定的需求没有实现。
2.如果没有任何实用程序可用于此问题,我正在考虑以下解决方案:
-在每个实体类(即Person)中,我将定义检测从该实体到其他实体的链接的所有检查方法,例如:
class Person {
// Properties
// Checking methods, return type and name of linked objects
public Map<String, String> getLinkedCars() {
// Query to DB to get linked cars
// return a Map contain Class name along with object name <Car, Ford Mustang>
}
public Map<String, String> getLinkedHouses() {
// Query to DB to get linked houses
// return a Map contain Class name along with object name <House, MyHouse>
}
}
班级人员{
//性质
//检查链接对象的方法、返回类型和名称
公共映射getLinkedCars(){
//查询数据库以获取链接的车辆
//返回包含类名和对象名的映射
}
公共地图GetLinkedHouse(){
//查询数据库以获取链接房屋
//返回包含类名和对象名的映射
}
}
-然后,在删除Person实体之前的服务中,我将使用反射机制收集检查方法(其名称以“getLinkedXXX”开头)的结果,并生成详细的错误消息。那么这个解决方案好吗?关于MVC的性能和约定(因为我必须在模型类中查询数据)?
感谢您的帮助。一种(不是那么简单)方法是扫描实体类中的
@OneToMany
或@ManyToMany
注释字段,并执行检查,以便向用户提供整洁的错误消息。下面的示例代码假定您只注释字段,而不是getters方法,例如:
public class Person {
@OneToMany(..)
private List<House> houses;
//...
}
然后迭代并检查@OneToMany
或@ManyToMany
注释
for(Field f : fields) {
if( f.getAnnotation(OneToMany.class) != null ||
f.getAnnotation(ManyToMany.class) != null) {
// Here you know f has to be checked before the person is deleted ...
}
}
可以使用以下方法获得特定person对象的字段值:
Person p = // fetch a person ..
Field f = // assume f is the "List<House> houses" field
List<House> houses = (List<House>) f.get(p);
Person p=//获取一个人。。
字段f=//假设f是“列表房屋”字段
列表房屋=(列表)f.get(p);
一种(并非如此简单)方法是扫描实体类中的@OneToMany
或@ManyToMany
注释字段,并执行检查,以便向用户提供整洁的错误消息。下面的示例代码假定您只注释字段,而不是getters方法,例如:
public class Person {
@OneToMany(..)
private List<House> houses;
//...
}
然后迭代并检查@OneToMany
或@ManyToMany
注释
for(Field f : fields) {
if( f.getAnnotation(OneToMany.class) != null ||
f.getAnnotation(ManyToMany.class) != null) {
// Here you know f has to be checked before the person is deleted ...
}
}
可以使用以下方法获得特定person对象的字段值:
Person p = // fetch a person ..
Field f = // assume f is the "List<House> houses" field
List<House> houses = (List<House>) f.get(p);
Person p=//获取一个人。。
字段f=//假设f是“列表房屋”字段
列表房屋=(列表)f.get(p);
我遇到了类似的问题,我必须检查实体是否可以安全删除,以避免违反外键约束。我就是这样解决的:
首先,我创建了一个注释来标记删除前需要检查的实体:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = SafeDeleteValidator.class)
public @interface SafeDelete {
String message() default "{lima.jefferson.SafeDelete.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
在实体类中,我使用了如下注释:
@SafeDelete(message = "Couldn't delete this entity due to...")
public class MyEntity {
@CheckForDelete
public Boolean checkForDelete() {
// Insert your business logic here
return true;
}
}
最后是SafeDelete
注释的验证器:
public class SafeDeleteValidator implements ConstraintValidator<SafeDelete, Object> {
@Override
public void initialize(SafeDelete constraintAnnotation) {
}
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
Method[] methods = object.getClass().getMethods();
return Arrays.stream(methods)
.filter(m -> m.getAnnotation(CheckForDelete.class) != null)
// Deal with the exception here
.map(m -> (Boolean) m.invoke(object))
.reduce(true, (a, b) -> a && b);
}
}
公共类SafeDeleteValidator实现ConstraintValidator{
@凌驾
公共无效初始化(安全删除约束旋转){
}
@凌驾
公共布尔值有效(对象、约束验证或上下文上下文){
方法[]方法=object.getClass().getMethods();
返回Arrays.stream(方法)
.filter(m->m.getAnnotation(CheckForDelete.class)!=null)
//在这里处理例外情况
.map(m->(布尔)m.invoke(对象))
.reduce(真,(a,b)->a和b);
}
}
然后,您可以按照此答案将验证仅应用于删除。我有一个类似的问题,我必须检查是否可以安全地删除实体以避免违反外键约束。我就是这样解决的: 首先,我创建了一个注释来标记删除前需要检查的实体:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = SafeDeleteValidator.class)
public @interface SafeDelete {
String message() default "{lima.jefferson.SafeDelete.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
在实体类中,我使用了如下注释:
@SafeDelete(message = "Couldn't delete this entity due to...")
public class MyEntity {
@CheckForDelete
public Boolean checkForDelete() {
// Insert your business logic here
return true;
}
}
最后是SafeDelete
注释的验证器:
public class SafeDeleteValidator implements ConstraintValidator<SafeDelete, Object> {
@Override
public void initialize(SafeDelete constraintAnnotation) {
}
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
Method[] methods = object.getClass().getMethods();
return Arrays.stream(methods)
.filter(m -> m.getAnnotation(CheckForDelete.class) != null)
// Deal with the exception here
.map(m -> (Boolean) m.invoke(object))
.reduce(true, (a, b) -> a && b);
}
}
公共类SafeDeleteValidator实现ConstraintValidator{
@凌驾
公共无效初始化(安全删除约束旋转){
}
@凌驾
公共布尔值有效(对象、约束验证或上下文上下文){
方法[]方法=object.getClass().getMethods();
返回Arrays.stream(方法)
.filter(m->m.getAnnotation(CheckForDelete.class)!=null)
//在这里处理例外情况
.map(m->(布尔)m.invoke(对象))
.reduce(真,(a,b)->a和b);
}
}
然后,您可以按照此答案将验证仅应用于删除。使用cascade=CascadeType。REMOVE@MasudCSECUET这不就是删除它而不提供任何错误消息的信息吗?将关联设置为双向的,您将在Person实体中直接将汽车和房屋的集合链接到汽车。也就是说,我不认为在任何情况下这样做都是合理的。如果您删除了一个打了3000个电话、有500个朋友的人,则不希望列出所有这些实体。不要在模型对象中进行数据库调用。在操作中使用dao/helper。@JBNizet:我只是在错误消息中显示一些顶级实体,而不是全部。那么,有没有办法检测从外部链接到此实体的所有外部约束?使用cascade=CascadeType。REMOVE@MasudCSECUET这难道不只是删除它而不提供任何错误消息的信息吗