代码之家  ›  专栏  ›  技术社区  ›  danny.lesnik

映射同一类关系-继续

  •  1
  • danny.lesnik  · 技术社区  · 15 年前

    这篇文章是这篇文章的延续 post

    我有dluser类,这个类的每个对象可能有dlfacebook类,dlfacebook的每个对象可以有映射为myfriends的朋友。

    我尝试使用包映射、复合主键和静态内部类来映射同一类的多对多关系。我的代码如下:

    public class DlUser{
     public DlUser(){}
     Long Id;
     String FirstName;
     String LastName;
     ....
     DlFaceBook fbuser;
     //// all requred 
     getters and setters...
    }
    

    Facebook用户类看起来像这样,你可以看到我和我的朋友类有一个对象集合:

    public class DlFaceBook {
    private long dlpId;
    private String FbId;
    private Collection<MyFriends> Friends;
    public DlFaceBook(){}
    public void setFbId(String FbId)
    {
        this.FbId = FbId;
    }
    public void setFriends(Collection<MyFriends> friends)
    {
        this.Friends = friends;
    }
    public Collection<MyFriends> getFriends()
    {
        return this.Friends;
    }
    public void setdlpId(long id)
    {
        this.dlpId = id;
    }
    public long getdlpId()
    {
        return this.dlpId;
    }
    public String getFbId()
    {
        return this.FbId;
    }
    }
    

    我的朋友班级如下:

    public class MyFriends {
    
        private MyFriendsId myFriendId;
    
        private DlFaceBook me;
        private DlFaceBook myFriend;
       public MyFriendsId getmyFriendId(){
            return this.myFriendId;
       }
       public void setmyFriendId(MyFriendsId fid){
        this.myFriendId = fid;
       }
    
        public void setme(DlFaceBook me){
          this.me = me;
       }
       public void setmyFriend(DlFaceBook friend){
              this.myFriend = friend;
           }
       public DlFaceBook getme(){
              return this.me ;
           }
           public DlFaceBook getmyFriend(){
                  return this.myFriend ;
               }
        public MyFriends(DlFaceBook me, DlFaceBook user){
            this.me = me ;
            this.myFriend = user;
            this.myFriendId = new MyFriendsId(me.getdlpId(),user.getdlpId());
        }
        public static class MyFriendsId implements Serializable {
    
            private long meId;
            private long myFrId;
    
            // getter's and setter's
    
            public MyFriendsId() {}
            public MyFriendsId(long meId, long myFriendId) {
                this.meId = meId;
                this.myFrId = myFriendId;
            }
    
            // getter's and setter's
            public long getmeId(){
                return this.meId;
            }
            public void setmeId(Integer id){
                this.meId = id;
            }
    
            public long getmyFrId(){
                return this.myFrId;
            }
            public void setmyFrId(long id){
                this.myFrId = id;
            }
        }
    } 
    

    现在的映射:

    dluser.hbm.xml如下,它很简单:

    <hibernate-mapping>
      <class name="DlUser" table="Users">
      <id name="Id" column="id" >
    <generator class="sequence">
                    <param name="sequence">userseq</param>
                </generator>        
     </id>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
     <property name="firstName">
         <column name="FirstName" />
      </property>
      <property name="lastName">
        <column name="LastName"/>
      </property>
     <many-to-one
                name="FaceBook"
                class="DlFaceBook"
                cascade="all"
                column="dlpId"
                unique="true" 
            />
     </class>
    </hibernate-mapping>
    

    dlfacebook.hbm.xml如下所示:

    <hibernate-mapping>
      <class name="DlFaceBook" table="dlfacebook">
     <id name="dlpId" type="java.lang.Long" column="dlpId">
    <generator class="increment" />
    </id>
       <property name="fbId">
         <column name="fbId" />
      </property>
         <bag name="Friends"> 
                <key column="me_Id" />
                <one-to-many class="MyFriends"/>
            </bag>
     </class>
    </hibernate-mapping>
    

    然后myfriends.hbm.xml如下所示:

    <hibernate-mapping>
      <class name="MyFriends">
      <composite-id name="myFriendId" class="MyFriends$MyFriendsId">
            <key-property name="meId"/>
            <key-property name="myFrId"/>
        </composite-id>
        <many-to-one name="me" class="DlFaceBook" insert="false" update="false"/>
        <many-to-one name="myFriend" class="DlFaceBook" insert="false" update="false"/>
        </class>
        </hibernate-mapping>
    

    执行查询时,出现以下错误:

    Hibernate: insert into dlfacebook (fbId, dlpId) values (?, ?)
    Hibernate: insert into Users (FirstName, LastName, email, twitter, birthday, dlpId, id) values (?, ?, ?, ?, ?, ?, ?)
    Hibernate: update MyFriends set me_Id=? where meId=? and myFrId=?
    Hibernate: update MyFriends set me_Id=? where meId=? and myFrId=?
    Oct 2, 2010 1:21:18 PM org.hibernate.jdbc.BatchingBatcher doExecuteBatch
    SEVERE: Exception executing batch: 
    org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
        at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
        at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
        at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:90)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:183)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
        at Test.main(Test.java:54)
    Oct 2, 2010 1:21:18 PM org.hibernate.event.def.AbstractFlushingEventListener performExecutions
    SEVERE: Could not synchronize database state with session
    org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
        at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
        at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
        at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:90)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:183)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
        at Test.main(Test.java:54)
    Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    

    我看到当我们试图更新不存在的行时会发生这个错误,但是我如何使这个代码工作呢?

    1 回复  |  直到 15 年前
        1
  •  3
  •   Arthur Ronald    15 年前

    只有Facebook和我的朋友

    脸谱网 注意添加便利方法和mutablelong(稍后,我告诉您为什么使用mutablelong)

    public class Facebook {
    
        private MutableLong id = new MutableLong();
        public Long getId() { return id.longValue(); }
        public void setId(Long id) { this.id.setValue(id); }
    
        public MutableLong getIdAsMutableLong() {
            return id;
        }
    
        private Collection<MyFriends> myFriends = new ArrayList<MyFriends>();
        public Collection<MyFriends> getMyFriends() { return myFriends; }
        public void setMyFriends(Collection<MyFriends> myFriends) { this.myFriends = myFriends; }
    
        /**
         * add convenience method
         */
        public void addFriend(Facebook myFriendFacebook) {
            myFriends.add(new MyFriends(this, myFriendFacebook));
        }
    
    }
    

    我的朋友们

    public class MyFriends {
    
        private MyFriendsId myFriendId;
        public MyFriendsId getmyFriendId(){ return this.myFriendId; }
        public void setmyFriendId(MyFriendsId myFriendId){ this.myFriendId = myFriendId; }
    
        private Facebook me;
        public Facebook getme() { return this.me; }
        public void setme(Facebook me){ this.me = me; }
    
        private Facebook myFriend;
        public Facebook getmyFriend() { return this.myFriend; }
        public void setmyFriend(Facebook friend) { this.myFriend = friend; }
    
        public MyFriends() {}
        public MyFriends(Facebook meFacebook, Facebook myFriendFacebook){
            this.me = meFacebook ;
            this.myFriend = myFriendFacebook;
    
            this.myFriendId = new MyFriendsId(meFacebook.getIdAsMutableLong(), myFriendFacebook.getIdAsMutableLong());
        }
    
        public static class MyFriendsId implements Serializable {
    
            private MutableLong meId = new MutableLong();
            public Long getMeId() { return this.meId.longValue(); }
            public void setMeId(Long id) { this.meId.setValue(id); }
    
            private MutableLong myFriendId = new MutableLong();
            public Long getMyFriendId(){ return this.myFriendId.longValue(); }
            public void setMyFriendId(Long id) { this.myFriendId.setValue(id); }
    
            public MyFriendsId() {}
            public MyFriendsId(MutableLong meId, MutableLong myFriendId) {
                this.meId = meId;
                this.myFriendId = myFriendId;
            }
    
            @Override
            public boolean equals(Object o) {
                if (!(o instanceof MyFriendsId))
                    return false;
    
                MyFriendsId other = (MyFriendsId) o;
                return new EqualsBuilder()
                           .append(getMeId(), other.getMeId())
                           .append(getMyFriendId(), getMyFriendId())
                           .isEquals();
            }
    
            @Override
            public int hashCode() {
                return new HashCodeBuilder()
                           .append(getMeId())
                           .append(getMyFriendId())
                           .hashCode();
            }
    
        }
    }
    

    映射

    <hibernate-mapping package="br.com._3845772.model.domain">
        <class name="User">
            <id name="id">
                <generator class="native"/>
            </id>
            <many-to-one cascade="all" class="Facebook" name="facebook"/>
        </class>
        <class name="Facebook">
            <id name="id">
                <generator class="native"/>
            </id>
            <bag cascade="all" name="myFriends">
                <key column="ME_FACEBOOK_ID" update="false"/>
                <one-to-many class="MyFriends"/>
            </bag>
        </class>
        <class name="MyFriends">
            <composite-id class="MyFriends$MyFriendsId" name="myFriendId">
                <key-property column="ME_FACEBOOK_ID" name="meId"/>
                <key-property column="MY_FRIEND_FACEBOOK_ID" name="myFriendId"/>
            </composite-id>
            <many-to-one class="Facebook" column="ME_FACEBOOK_ID" insert="false" name="me" update="false"/>
            <many-to-one class="Facebook" column="MY_FRIEND_FACEBOOK_ID" insert="false" name="myFriend" update="false"/>
        </class>
    </hibernate-mapping>
    

    这个样本

    Facebook meFacebook = new Facebook();
    Facebook myFriendFacebook = new Facebook();
    
    meFacebook.addFriend(myFriendFacebook);
    
    Session session = sessionFactory.openSession();
    session.beginTransaction();
    
    session.save(myFriendFacebook);
    session.save(meFacebook);
    
    session.getTransaction().commit();
    session.close();
    

    给我

    Hibernate: insert into Facebook values ( )
    Hibernate: insert into Facebook values ( )
    Hibernate: select myfriends_.ME_FACEBOOK_ID, myfriends_.MY_FRIEND_FACEBOOK_ID from MyFriends myfriends_ where myfriends_.ME_FACEBOOK_ID=? and myfriends_.MY_FRIEND_FACEBOOK_ID=?
    Hibernate: insert into MyFriends (ME_FACEBOOK_ID, MY_FRIEND_FACEBOOK_ID) values (?, ?)
    

    几张纸条

    • 冬眠 不支持 自动生成复合主键。 你必须 在保存前设置其值
    • 你的数据库 必须支持目标生成器策略 (如果您不知道您的数据库支持哪种生成器策略,最好使用 本地的 策略
    • 每个实体 必须提供无参数构造函数

    为什么变长( 包封的 用长的财产)而不是长的?

    数字及其子类(long是数字) 是不可变的 . 所以,如果你想要facebook.id(由数据库配置)及其对应的myfriend$myfriend id.meid 共享相同的值,必须使用mutablelong . 当数据库设置facebook.id时,myfriend$myfriend id.meid会自动获取其最新值。但如果你用的是可变长的。