使用多列sql类型CHAR来休眠一对多单向关系

时间:2014-01-30 12:18:39

标签: hibernate jpa

我有两个名为“Padre”和“Figlio”的实体 Padre是老板,Figlio是小孩 Padre的主键有两列,PADREK1和PADREK2,都是CHAR(20) Figlio的主键有四列: PADREPADREK1(外国)CHAR(20) PADREPADREK2(外国)CHAR(20) FIGLIOK1 CHAR(20) FIGLIOK2 CHAR(20)

这是我的实体类的代码

    public class PadreBean extends BaseEntityBean3 implements Serializable
    {
       @EmbeddedId
       PadrePK iPadrePK;
       @Column(name = "DESCRIPTION")
       private String iDescription;
       @Column(name = "ABSUNIQUEID")
       private long iABSUniqueId;
       @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
       @JoinColumns(
          {
             @JoinColumn(name = "ABSOUTQUEUENAME", nullable = true)
          })
       private ABSOutQueueBean iAbsOutQueueBean;
       @OneToMany(fetch = FetchType.LAZY)
       @JoinColumns({
          @JoinColumn(name = "PADREPADREK1", referencedColumnName = "PADREK1"),
          @JoinColumn(name = "PADREPADREK2", referencedColumnName = "PADREK2")
       })
       List iFiglioBeans;
       ......

iFiglioBeans是孩子们的集合

问题是: 如果Padre的主键列都使用全部20个字符填充,则一切正常; id padre的主键列未完全填充Hibernate会加载集合 但加载后它会清除其内容。

我已经激活了Hibernate日志记录,当我的代码访问子集合时,我看到:


    [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] (http-localhost/127.0.0.1:8080-1) Obtaining JDBC connection
    [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] (http-localhost/127.0.0.1:8080-1) Obtained JDBC connection
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Result set contains (possibly empty) collection: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1, iPadreK1=p1}]
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Result set row: 0
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Result row: EntityKey[com.dat.abs.run.FiglioBean#component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=1                   , iPadrePadreK1=p1                  , iFiglioK1=1                   , iPadrePadreK2=p1                  }]
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Found row of collection: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1                  , iPadreK1=p1                  }]
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Result set row: 1
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Result row: EntityKey[com.dat.abs.run.FiglioBean#component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=f1                  , iPadrePadreK1=p1                  , iFiglioK1=f1                  , iPadrePadreK2=p1                  }]
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Found row of collection: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1                  , iPadreK1=p1                  }]
    [org.hibernate.engine.internal.TwoPhaseLoad] (http-localhost/127.0.0.1:8080-1) Resolving associations for [com.dat.abs.run.FiglioBean#component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=1                   , iPadrePadreK1=p1                  , iFiglioK1=1                   , iPadrePadreK2=p1                  }]
    [org.hibernate.engine.internal.TwoPhaseLoad] (http-localhost/127.0.0.1:8080-1) Done materializing entity [com.dat.abs.run.FiglioBean#component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=1                   , iPadrePadreK1=p1                  , iFiglioK1=1                   , iPadrePadreK2=p1                  }]
    [org.hibernate.engine.internal.TwoPhaseLoad] (http-localhost/127.0.0.1:8080-1) Resolving associations for [com.dat.abs.run.FiglioBean#component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=f1                  , iPadrePadreK1=p1                  , iFiglioK1=f1                  , iPadrePadreK2=p1                  }]
    [org.hibernate.engine.internal.TwoPhaseLoad] (http-localhost/127.0.0.1:8080-1) Done materializing entity [com.dat.abs.run.FiglioBean#component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=f1                  , iPadrePadreK1=p1                  , iFiglioK1=f1                  , iPadrePadreK2=p1                  }]
    [org.hibernate.engine.loading.internal.CollectionLoadContext] (http-localhost/127.0.0.1:8080-1) 2 collections were found in result set for role: com.dat.abs.run.PadreBean.iFiglioBeans
    [org.hibernate.engine.loading.internal.CollectionLoadContext] (http-localhost/127.0.0.1:8080-1) Collection fully initialized: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1, iPadreK1=p1}]
    [org.hibernate.engine.loading.internal.CollectionLoadContext] (http-localhost/127.0.0.1:8080-1) Collection fully initialized: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1                  , iPadreK1=p1                  }]
    [org.hibernate.engine.loading.internal.CollectionLoadContext] (http-localhost/127.0.0.1:8080-1) 2 collections initialized for role: com.dat.abs.run.PadreBean.iFiglioBeans
    [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] (http-localhost/127.0.0.1:8080-1) Releasing JDBC connection
    [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] (http-localhost/127.0.0.1:8080-1) Released JDBC connection
    [org.hibernate.loader.Loader] (http-localhost/127.0.0.1:8080-1) Done loading collection
    [org.hibernate.event.internal.AbstractFlushingEventListener] (http-localhost/127.0.0.1:8080-1) Processing flush-time cascades
    
    [org.hibernate.event.internal.AbstractFlushingEventListener] (http-localhost/127.0.0.1:8080-1) Dirty checking collections
    [org.hibernate.engine.internal.Collections] (http-localhost/127.0.0.1:8080-1) Collection found: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1, iPadreK1=p1}], was: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1, iPadreK1=p1}] (initialized)
    [org.hibernate.engine.internal.Collections] (http-localhost/127.0.0.1:8080-1) Found collection with unloaded owner: [com.dat.abs.run.PadreBean.iFiglioBeans#component[iPadreK1,iPadreK2]{iPadreK2=p1                  , iPadreK1=p1                  }]
    [org.hibernate.event.internal.AbstractFlushingEventListener] (http-localhost/127.0.0.1:8080-1) Flushed: 0 insertions, 0 updates, 0 deletions to 4 objects
    [org.hibernate.event.internal.AbstractFlushingEventListener] (http-localhost/127.0.0.1:8080-1) Flushed: 0 (re)creations, 0 updates, 0 removals to 2 collections
    [org.hibernate.internal.util.EntityPrinter] (http-localhost/127.0.0.1:8080-1) Listing entities:
    [org.hibernate.internal.util.EntityPrinter] (http-localhost/127.0.0.1:8080-1) com.dat.abs.run.FiglioBean{iDescrizioneFiglio=                    , iFiglioPK=component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=1                   , iPadrePadreK1=p1                  , iFiglioK1=1                   , iPadrePadreK2=p1                  }, iABSUniqueId=249}
    [org.hibernate.internal.util.EntityPrinter] (http-localhost/127.0.0.1:8080-1) com.dat.abs.run.ABSOutQueueBean{iCreationDateTime=2012-02-17 07:51:10.0, iLastUpdateUser=null, iCreationUser=system                   , iLastUpdateDateTime=null, iPrintServiceName=null, iId=component[iName]{iName=#01                 }, iDescription=01                                                }
    [org.hibernate.internal.util.EntityPrinter] (http-localhost/127.0.0.1:8080-1) com.dat.abs.run.FiglioBean{iDescrizioneFiglio=f1                  , iFiglioPK=component[iFiglioK1,iFiglioK2,iPadrePadreK1,iPadrePadreK2]{iFiglioK2=f1                  , iPadrePadreK1=p1                  , iFiglioK1=f1                  , iPadrePadreK2=p1                  }, iABSUniqueId=248}
    [org.hibernate.internal.util.EntityPrinter] (http-localhost/127.0.0.1:8080-1) com.dat.abs.run.PadreBean{iPadrePK=component[iPadreK1,iPadreK2]{iPadreK2=p1, iPadreK1=p1}, iAbsOutQueueBean=com.dat.abs.run.ABSOutQueueBean#component[iName]{iName=#01                 }, iDescription=p1                  , iABSUniqueId=247, iFiglioBeans=[]}
    [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] (http-localhost/127.0.0.1:8080-1) Releasing JDBC connection
    [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] (http-localhost/127.0.0.1:8080-1) Aggressively releasing JDBC connection
    

正如您所看到的,Hibernate首先加载了孩子,但是在清除它之后。 请参阅该行前面附带的日志:找到带有已卸载所有者的集合:消息

问题是DBM用来填充CHARs列的空白区域,我已经说过了,如果我在我的键列中插入所有字符也一样。

那么,是否有一个解决方案让Hibernate的子集合使用CHAR列作为未完全填充的主键?

提前感谢您的时间

1 个答案:

答案 0 :(得分:1)

我已经解决了编写自己的用户类型的问题。 我在这里发帖因为可能对其他人有用。 使用db2 9.x和Oracle 12c进行测试


    package com.dat.abs.run;

    import java.io.Serializable;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Types;

    import org.hibernate.HibernateException;
    import org.hibernate.engine.spi.SessionImplementor;
    import org.hibernate.usertype.UserType;

    public class ABSChar implements UserType
    {
       public int[] sqlTypes()
       {
          return new int[]
             {
                Types.CHAR,
             };
       }
       public Class returnedClass()
       {
          return String.class;
       }
       public boolean equals(Object x, Object y) throws HibernateException
       {
          return (x == y) || (x != null && y != null && (x.equals(y)));
       }
       public Object deepCopy(Object value) throws HibernateException
       {
          if (value == null)
             return null;
          return new String((String) value);
       }
       public boolean isMutable()
       {
          return false;
       }
       @Override
       public int hashCode(Object aValue) throws HibernateException
       {
          return aValue.hashCode();
       }
       @Override
       public Object replace(Object aOriginal, Object aTarget, Object aOwner) throws HibernateException
       {
          return aOriginal;
       }
       @Override
       public Object assemble(Serializable aChaced, Object aOwner) throws HibernateException
       {
          return aChaced;
       }
       @Override
       public Serializable disassemble(Object aValue) throws HibernateException
       {
          return (Serializable) aValue;
       }
       @Override
       public Object nullSafeGet(ResultSet aRs, String[] aNames, SessionImplementor aSession, Object aOwner) throws HibernateException, SQLException
       {
          String val = aRs.getString(aNames[0]);
          if (val == null)
          {
             return null;
          }
          return val.trim();
       }
       @Override
       public void nullSafeSet(PreparedStatement aStatament, Object aValue, int aIndex, SessionImplementor aSession) throws HibernateException, SQLException
       {
          aStatament.setString(aIndex, (String) aValue);
       }
    }

这是使用bean类中的类型


       @Type(type = "com.dat.abs.run.ABSChar")
       @Column(name = "PADREPADREK1", length = 20)
       private String iPadrePadreK1;
       @Type(type = "com.dat.abs.run.ABSChar")
       @Column(name = "PADREPADREK2", length = 20)
       private String iPadrePadreK2;
       @Type(type = "com.dat.abs.run.ABSChar")
       @Column(name = "FIGLIOK1", length = 20)
       private String iFiglioK1;
       @Type(type = "com.dat.abs.run.ABSChar")
       @Column(name = "FIGLIOK2", length = 20)