用户操作
[即时聊天] [发私信] [加为好友]
陈浩ID:cchheennhhaaoo119
16436次访问,排名7539(-7),好友36人,关注者54人。
放弃了篮球的程序员:代码是程序员的生命.
生活:生活如同强奸,与其拼命反抗,不如学会享受。
技术:性能 功能 效果是一个三角形.永远没有最佳形态.
状态:年轻的时候我和爸说,我要打一辈子篮球,因为我爱它!但现在我大了,由于工作带给我的压力和疲惫,使我在也不能象以前一样站在这片富有欢笑和洒满汗水的土地上。
cchheennhhaaoo119的文章
原创 97 篇
翻译 0 篇
转载 10 篇
评论 25 篇
最近评论
likerai7817:
我所做的项目也是这样用的。可在WEBLOGIC 9下好像不行,报以下错误。
Error 500--Internal Server Error
javax.servlet.jsp.JspException: Cannot find bean entry in any scope
likerai7817:
我所做的项目也是这样用的。可在WEBLOGIC 9下好像不行,报以下错误。
Error 500--Internal Server Error
javax.servlet.jsp.JspException: Cannot find bean entry in any scope
iwindyforest:Pretty Good!
qianli2008:谁有jbpm-starters-kit-3.1.2.zip啊,也发给我一份吧,发送ql2051002047@163.com中,不胜感激
myitlyj:dbpool.properties这个文件是怎么生成的////
文章分类
收藏
    相册
    北京游玩
    篮球生涯
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 hibernate的collections介绍收藏

    新一篇: aop 概述 AOP 权限控制 AOP 访问锁 | 旧一篇: js优化

    在Hibernate下,实体类将collection作为自己的一个逻辑单元,而不是被容纳的多个实体。这非常重要!它主要体现为以下几点:

    • 当删除或增加collection中对象的时候,拥有这个collection的实体对象的版本值会递增。

    • 如果一个从collection中移除的对象是一个值类型(value type)的实例,比如composite element,那么这个对象的持久化状态将会终止,其在数据库中对应的记录会被删除。同样的,向collection增加一个value type的实例将会使之立即被持久化。

    • 另一方面,如果从一对多或多对多关联的collection中移除一个实体,在缺省情况下这个对象并不会被删除。这个行为是完全合乎逻辑的--改变一个实体的内部状态不应该使与它关联的实体消失掉!同样的,向collection增加一个实体不会使之被持久化。

    实际上,向Collection增加一个实体的缺省动作只是在两个实体之间创建一个连接而已,同样移除的时候也只是删除连接。这种处理对于所有的情况都是合适的。不适合所有情况的其实是父子关系本身,因为子对象是否存在依赖于父对象的生存周期。

    1. 双向的一对多关系(Bidirectional one-to-many)

    让我们从一个简单的例子开始,假设要实现一个从类Parent到类Child的一对多关系。

    <set name="children">
        
    <key column="parent_id"/>
        
    <one-to-many class="Child"/>
    </set>

    如果我们运行下面的代码

    Parent p = new Parent ();
    Child c 
    = new Child();
    p.getChildren().add(c);
    session.save(c);
    session.flush();

    Hibernate就会产生下面的两条SQL语句:

    • 一条INSERT语句,用于创建对象c对应的数据库记录

    • 一条UPDATE语句,用于创建从对象p到对象c的连接

    这样做不仅效率低,而且违反了列parent_id非空的限制。我们可以通过在集合类映射上指定not-null="true"来解决非空约束的冲突:

    <set name="children">
        
    <key column="parent_id" not-null="true"/>
        
    <one-to-many class="Child"/>
    </set>

    当然,这并非是推荐的解决方法。

    底层的原因是,对象p到对象c的连接(外键parent_id)没有被当作是Child对象状态的一部分,也没有在INSERT的时候被创建。解决的办法是,在Child一端设置映射。

    <many-to-one name="parent" column="parent_id" not-null="true"/>

    (我们还需要为类Child添加parent属性)

    现在实体Child在管理连接的状态,为了使collection不更新连接,我们使用inverse属性。

    <set name="children" inverse="true">
        
    <key column="parent_id"/>
        
    <one-to-many class="Child"/>
    </set>

    下面的代码是用来添加一个新的Child

    Parent p = (Parent) session.load(Parent.class, pid);
    Child c 
    = new Child();
    c.setParent(p);
    p.getChildren().add(c);
    session.save(c);
    session.flush();

    现在,只会有一条INSERT语句被执行!

    为了让事情变得井井有条,可以为Parent加一个addChild()方法。

    public void addChild(Child c) ...

    现在,添加Child的代码就是这样

    Parent p = (Parent) session.load(Parent.class, pid);
    Child c 
    = new Child();
    p.addChild(c);
    session.save(c);
    session.flush();
    你看,代码是不是简洁明了了很多呢?

    2. 级联生命周期(Cascading lifecycle)

    对每个对象调用save()方法很麻烦,我们可以用级联来解决这个问题。

    <set name="children" inverse="true" cascade="all">
        
    <key column="parent_id"/>
        
    <one-to-many class="Child"/>
    </set>

    配置级联以后,代码就可以这样写:

    Parent p = (Parent) session.load(Parent.class, pid);
    Child c 
    = new Child();
    p.addChild(c);
    session.flush();

    同样的,保存或删除Parent对象的时候并不需要遍历其子对象。 下面的代码会删除对象p及其所有子对象对应的数据库记录。

    Parent p = (Parent) session.load(Parent.class, pid);
    session.delete(p);
    session.flush();

    然而,这段代码

    Parent p = (Parent) session.load(Parent.class, pid);
    Child c 
    = (Child) p.getChildren().iterator().next();
    p.getChildren().remove(c);
    c.setParent(
    null);
    session.flush();

    不会从数据库删除c;它只会删除与p之间的连接(并且会导致违反NOT NULL约束,在这个例子中)。你需要明确调用Childdelete()方法。

    Parent p = (Parent) session.load(Parent.class, pid);
    Child c 
    = (Child) p.getChildren().iterator().next();
    p.getChildren().remove(c);
    session.delete(c);
    session.flush();

    在我们的例子中,如果我们规定没有父对象的话,子对象就不应该存在,如果将子对象从collection中移除,实际上我们是想删除它。要实现这种要求,就必须使用cascade="all-delete-orphan"

    <set name="children" inverse="true" cascade="all-delete-orphan">
        
    <key column="parent_id"/>
        
    <one-to-many class="Child"/>
    </set>

    注意:即使在collection一方的映射中指定inverse="true",在遍历collection的时候级联操作仍然会执行。如果你想要通过级联进行子对象的插入、删除、更新操作,就必须把它加到collection中,只调用setParent()是不够的。

    3. 级联与未保存值(Cascades and unsaved-value

    假设我们从Session中装入了一个Parent对象,用户界面对其进行了修改,然后我们希望在一个新的Session里面调用update()来更新它。对象Parent包含了子对象的集合,由于打开了级联更新,Hibernate需要知道哪些子对象是新的,哪些是数据库中已经存在的。我们假设ParentChild对象的标识属性都是自动生成的,类型为java.lang.Long。Hibernate会使用标识属性的值,和version 或 timestamp 属性,来判断哪些子对象是新的,在 Hibernate3 中,显式指定unsaved-value不再是必须的了。

    下面的代码会更新parentchild对象,并且插入newChild对象。

    //parent and child were both loaded in a previous session
    parent.addChild(child);
    Child newChild 
    = new Child();
    parent.addChild(newChild);
    session.update(parent);
    session.flush();

    好的,对于自动生成标识的情况这样做很方便,但是自分配的标识和复合标识怎么办呢?这是有点麻烦,因为Hibernate没有办法区分新对象(标识被用户指定了)和前一个Session装入的对象。在这种情况下,Hibernate会使用timestamp或version属性,或者查询第二级缓存,或者最坏的情况,查询数据库,来确认是否此行存在。

    4. 结论

    这个问题往往让新手感到迷惑,它确实不太容易消化。不过,经过一些实践以后,你会感觉越来越顺手。父子对象模式已经被广泛的应用在Hibernate应用程序中。

     

    发表于 @ 2008年03月26日 16:56:00|评论(loading...)|编辑

    新一篇: aop 概述 AOP 权限控制 AOP 访问锁 | 旧一篇: js优化

    评论

    #iwindyforest 发表于2008-07-08 04:39:59  IP: 124.42.77.*
    Pretty Good!
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © cchheennhhaaoo119