我正在尝试使用 Java/Spring MVC 和 Hibernate 在我的 Web 应用程序中设置一个简单的 EAV 模式。我似乎无法弄清楚这种情况下 hibernate XML 设置背后的魔力。

我的数据库表“SETUP”有三列:

  • 用户 ID (FK)
  • setup_item
  • 设置值

  • 数据库复合键由 组成用户 ID | setup_item

    这是 Setup.java 类:
    public class Setup implements CommonFormElements, Serializable { 
      private Map data = new HashMap(); 
      private String saveAction; 
      private Integer speciesNamingList; 
      private User user; 
     
      Logger log = LoggerFactory.getLogger(Setup.class); 
     
      public String getSaveAction() { 
        return saveAction; 
      } 
     
      public void setSaveAction(String action) { 
        this.saveAction = action; 
      } 
     
      public User getUser() { 
        return user; 
      } 
     
      public void setUser(User user) { 
        this.user = user; 
      } 
     
      public Integer getSpeciesNamingList() { 
        return speciesNamingList; 
      } 
     
      public void setSpeciesNamingList(Integer speciesNamingList) { 
        this.speciesNamingList = speciesNamingList; 
      } 
     
      public Map getData() { 
        return data; 
      } 
     
      public void setData(Map data) { 
        this.data = data; 
      } 
    }

    我对 Hibernate 设置的问题是,我似乎无法弄清楚如何映射出外键和映射键将构造表的复合键的事实......这是由于缺乏使用 Hibernate 的经验。这是我使这个工作的初步尝试:


    <composite-id> 
      <key-many-to-one foreign-key="id" name="user" column="user_id" class="Business.User"> 
        <meta attribute="use-in-equals">true</meta> 
      </key-many-to-one> 
    </composite-id> 
     
    <map lazy="false" name="data" table="setup"> 
      <key column="user_id" property-ref="user"/> 
      <composite-map-key class="Command.Setup"> 
        <key-property name="data" column="setup_item" type="string"/> 
      </composite-map-key> 
     
      <element column="setup_value" not-null="true" type="string"/> 
    </map> 
    


    任何有关如何正确映射这种常见场景的见解将不胜感激!

    请您参考如下方法:

    如您所见,您有一个 不一致 映射

    你说 Setup 类定义了一个复合主键(注意我已经创建了一个复合主键类(SetupId - 见下文),它必须实现 Serializable 和 equals 和 hashcode 方法)

    package ar.domain; 
     
    import java.io.Serializable; 
    import java.util.HashMap; 
    import java.util.Map; 
     
    public class Setup implements Serializable { 
     
        private SetupId setupId; 
     
        private User user; 
        private Map data= new HashMap(); 
     
        public SetupId getSetupId() { 
            return setupId; 
        } 
     
        public void setSetupId(SetupId setupId) { 
            this.setupId = setupId; 
        } 
     
        public User getUser() { 
            return user; 
        } 
     
        public void setUser(User user) { 
            this.user = user; 
        } 
     
        public Map getData() { 
            return data; 
        } 
     
        public void setData(Map data) { 
            this.data = data; 
        } 
     
     
        public static class SetupId implements Serializable { 
     
            private Integer userId; 
            private String setupItem; 
     
            public String getSetupItem() { 
                return setupItem; 
            } 
     
            public void setSetupItem(String setupItem) { 
                this.setupItem = setupItem; 
            } 
     
            public Integer getUserId() { 
                return userId; 
            } 
     
            public void setUserId(Integer userId) { 
                this.userId = userId; 
            } 
     
            @Override 
            public boolean equals(Object o) { 
                if (o == null) 
                    return false; 
     
                if (!(o instanceof SetupId)) 
                    return false; 
     
                final SetupId other = (SetupId) o; 
                if (!(getUserId().equals(other.getUserId()))) 
                    return false; 
                if (!(getSetupItem().equals(other.getSetupItem()))) 
                    return false; 
     
                return true; 
            } 
     
            @Override 
            public int hashCode() { 
                int hash = 7; 
                hash = 11 * hash + (getUserId() != null ? getUserId().hashCode() : 0); 
                hash = 11 * hash + (getSetupItem() != null ? getSetupItem().hashCode() : 0); 
                return hash; 
            } 
     
        } 
     
    } 
    

    因为你的 Setup 类有一个值类型的 Map,你 应该定义其复合外键 定义其关系时(见关键要素)
    <class name="ar.domain.Setup"> 
        <composite-id name="setupId" class="ar.domain.Setup$SetupId"> 
            <key-property name="setupItem" type="string" column="SETUP_ITEM"/> 
            <key-property name="userId" type="integer" column="USER_ID"/> 
        </composite-id> 
        <many-to-one name="user" class="ar.domain.User" column="USER_ID" insert="false" update="false"/> 
        <map name="data" table="DATA_TABLE"> 
            <key> 
                <column name="SETUP_ITEM"/> 
                <column name="USER_ID"/> 
            </key> 
            <map-key column="USER_ID"/> 
            <element column="SETUP_VALUE" not-null="true" type="string"/> 
        </map> 
    </class> 
    

    并且,同时,使用复合外键列作为映射键(USER_ID,对吗?)这是没有意义的。为什么 ?
  • hibernate 不允许 您更新(复合)主键列

  • 除此之外,Hibernate 不支持自动生成 复合主键

    假设这里有你的 SETUP Table
    SETUP_ITEM USER_ID 
    0          1 
    0          2 
    

    还有你的 DATA_TABLE
    SETUP_ITEM USER_ID 
    0          1 
    

    如果您尝试以下方法会发生什么
    Integer userId = 3; 
    String setupValue = "someValue"; 
     
    setup.getData().put(userId, setupValue); 
    

    因为 SETUP Table 没有定义一个值为 3 的 USER_ID,你会看到一个 违反约束 .

    记在心上

    When you have a (composite) primary key, which can not be updatable, avoid to use it, someway, to change a mutable property which depends on it. Otherwise, Hibernate will complain it.


    评论关闭
    IT干货网

    微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!