代码之家  ›  专栏  ›  技术社区  ›  Thomas Jung

检查hibernate映射类中的不变量

  •  10
  • Thomas Jung  · 技术社区  · 16 年前

    使用hibernate的一个挑战是,管理类必须具有 问题在于,没有明确的点来初始化类并检查不变量。

    如果一个类具有依赖于多个属性的不变量,那么类的设计就会变得复杂。让我们从假设的绿地设计开始:

    public class A { 
        private int x; 
        private int y; 
    
        public A(int x, int y) { 
            this.x = x; 
            this.y = y; 
            checkInvariants(this.x, this.y); 
        } 
    
        private void checkInvariants(int x, int y) { 
            if (x + y « 0) throw new IllegalArgumentException(); 
        } 
    }
    

    这是不符合hibernate要求的基本实现。在构造函数中检查不变量。(checkInvariants()方法的内容并不重要,它只是用来说明类不变量可以依赖于多个属性。)

    new A(0, 0); 
    new A(-1, 0); //invalid 
    

    私有默认构造函数 (我省略了hibernate映射。)

    public class H { 
        int x; 
        int y; 
    
        public H(int x, int y) { 
            this.x = x; 
            this.y = y; 
            checkInvariants(this.x, this.y); 
        } 
    
        H(){} 
    
        private void checkInvariants(int x, int y) { 
            if (x + y « 0) throw new IllegalArgumentException(); 
        } 
    } 
    

    (休眠)。理想情况下,类不知道它的调用者。 如果满足不变量。您信任从数据库加载的数据,这是有问题的。即使您的应用程序是唯一使用此特定数据库模式的应用程序,管理员也始终有可能进行临时更改。

    检查用户代码中的不变量 :

    public class I { 
        private int x; 
        private int y; 
    
        public I() {} 
    
        public void checkInvariants() { 
            if (x + y « 0) throw new IllegalArgumentException(); 
        } 
    
        public void setX(int x){ 
            this.x = x; 
        } 
    
        public void setY(int y){ 
            this.y = y; 
        } 
    } 
    
    I i = new I(); 
    i.setX(-1); 
    i.setY(0); 
    i.checkInvariants(); 
    

    显然,这使得用户代码 更复杂 容易出错

    • 不太复杂
    • 对用户没有明确的了解
    • 不依赖hibernate框架?

    我想,为了达成务实的解决方案,必须放宽一些限制。唯一的硬约束是不依赖于hibernate框架。(域对象外的hibernate特定代码是可以的)。

    3 回复  |  直到 16 年前
        1
  •  5
  •   ChssPly76    16 年前

    您开始实现以下代码 理想情况下,一个类不知道它的 呼叫者。

    你在这里使用“依赖性”这个词有点快和松散。Hibernate不是一个“客户端”;这是一个框架 (作为开发人员/架构师/你有什么)选择用来实现你的持久性。因此,您将在某个地方有一些使用(因此依赖于)Hibernate的代码。也就是说,有

    此解决方法的一个具体问题 是由发起的实例吗 如果满足条件,则不检查hibernate 不变量。您信任数据 这是有问题的。即使你 应用程序是唯一使用此功能的应用程序 存在特定的数据库模式

    不必“信任” 数据(详见下文)。然而,我认为这个论点没有道理。如果你在多个应用程序中修改数据,你应该在一些常见的较低层进行验证,而不是依赖每个单独的应用程序来验证数据。所述公共层可以是数据库本身(在简单的情况下),也可以是提供供多个应用程序使用的公共API的服务层。

    直接 作为数据库的一部分

    尽管如此,如果你确实想在对象被验证时验证它们 ,实现起来相当简单。定义a Valid validate() 方法,并让每个相关的域对象实现它。您可以从以下位置调用该方法:

    1. 加载对象后的DAO/服务。
    2. Hibernate Interceptor or Listener -两者都是在Hibernate配置中设置的;您需要做的就是实现其中之一,以检查正在加载的对象是否实现
    3. Hibernate Validator

    直接 。原因很简单——只有在以下情况下才有意义 实体(因为一旦你有了setter,你就必须处理验证),因此意味着要做很多工作(处理构造函数参数映射等……),才能实现几乎为零的净效应。事实上,如果你 关注不可变对象的无参数构造函数,你总是不能将它们映射为实体,而是通过HQL加载它们 支持 constructor injection :

    select new A(x, y) from ...
    

    (针对托马斯评论中的要点):

    1. 我只是为了完整起见才提到拦截器;在这种情况下,听众更合适。 PostLoadEventListener 在实体完全初始化后调用。
    2. StringUtil.compare() 查询 。例如,在用于报告的“只读”查询中(即使如此,在许多情况下,通过API更合适)。但手动数据
    3. 可变性使构造函数注入 无关的 我并不是说你不能有非默认构造函数——你可以,也可以在代码中使用它。但是,如果你有setter方法,你就不能使用构造函数进行验证,所以它是否存在并不重要。
    4. HQL建设者注入和关联。 select new A(x, y, new B(c, d)) ;因此,为了获取关联,您需要将它们作为select子句中的实体检索,这意味着它们本身不需要arg构造函数:-)或者您可以在“main”实体上有一个构造函数,它将所有需要的嵌套属性作为参数,并在内部构造/填充关联,但这近乎疯狂:-)
        2
  •  3
  •   GDR    16 年前

    关系数据的基础原则 建模,我们可以完全自信 摘自斯蒂芬·法鲁特的《Sql的艺术》一书

    您的数据库应该包含有效的事实或真相,从数据库加载的数据不需要任何额外的验证,从数据库中提取的数据应该足够好。

        3
  •  2
  •   D Adler    16 年前

    public int getX(){ 
        return x; 
    } 
    
    public int getY(){ 
        return y; 
    } 
    
    public void doSomething(){
        x = x + y;
    }
    

    private boolean validated = false;
    
    public int getX(){ 
        if (!validated) {
            checkInvariants();
        }
    
        return x; 
    } 
    
    public int getY(){ 
        if (!validated) {
            checkInvariants();
        }
        return y; 
    } 
    
    public void doSomething(){
        if (!validated) {
            checkInvariants();
        }
        x = x + y;
    }
    
    public void checkInvariants() { 
        validated = true;
        if (x + y « 0) throw new IllegalArgumentException(); 
    }
    

    如果需要,您可以将“if(!validated)”移动到checkInvariants()中。

    您也可以查看Hibernate验证器,尽管它可能不符合您的框架独立性要求。 http://docs.huihoo.com/hibernate/annotations-reference-3.2.1/validator.html