映射相同的类关系 - 延续

时间:2010-10-02 12:49:18

标签: java hibernate orm

这篇文章是此post

的延续

我有DlUser Class这个类的每个对象都可能有DLFaceBook类,而DlFaceBook的每个对象都可以有Friends映射为myFriends。

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

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

Facebook用户类看起来像这样你可以看到我拥有MyFriends类的对象集合:

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;
}
}

MyFriends课程如下:

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 个答案:

答案 0 :(得分:3)

Facebook和MyFriends

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));
    }

}

<强> MyFriends

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 (?, ?)

几个笔记

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

现在为什么MutableLong(由long属性封装)而不是Long?

Number及其子类(Long是数字)是不可变的。因此,如果您希望Facebook.id(由数据库配置)及其对应的MyFriend $ MyFriendId.meId 共享相同的值,则必须使用MutableLong 。当数据库设置Facebook.id时,MyFriend $ MyFriendId.meId自动获得其最新值。但是如果你使用MutableLong就会发生这种情况。