【问题标题】:Mapping same class relation - continuation映射相同的类关系 - 继续
【发布时间】:2010-10-02 12:49:17
【问题描述】:

这篇文章是post的延续

我有 DlUser 类,这个类的每个对象都可能有 DLFaceBook 类,并且 DlFaceBook 的每个对象都可以有映射为 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

我看到当我们尝试更新不存在的行时会发生此错误,但我怎样才能使此代码正常工作?

【问题讨论】:

  • 如果您尝试更新不存在的行,这将如何工作?

标签: java hibernate orm


【解决方案1】:

只有 Facebook 和我的朋友

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

一些注意事项

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

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

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

【讨论】:

  • 它有效 :) 非常感谢。我从你的例子中学到了很多。这对我来说非常高兴。
  • 1) 这对我不起作用(更改MyFriends 表中一个复合键的值会导致在该表中创建新记录,删除根本不起作用)。 2)这个解决方案可能有效,但仅用于将新记录保存到MyFriends 表中。当Facebook 实体从数据库加载时,Hibernate 调用MyFriendsId 上的默认构造函数,因此MyFriendsId.meIdMyFriendsId.myFriendId 为空,并且在某些时候会抛出空异常。在默认构造函数中创建新实例会破坏使用 Mutable 的目的?对象作为 ID(值仍未共享)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
相关资源
最近更新 更多