簡體   English   中英

如何休眠注釋地圖 <String, Set<String> &gt;或地圖 <String, Map<String, String> &gt;

[英]How to Hibernate annotate Map<String, Set<String>> or Map<String, Map<String, String>>

使用Hibernate Core 4.1.7,JPA annotations,java 1.7

關於Map <String,Entity>讀取集合上的 Hibernate doc ,或Map <String,String> here(stackoverflow)的例子很簡單。

很難找到Map<String, Set<String>>上的例子(或者甚至是Map <String,Map <String,String >>只是為了好奇關於菊花變換)為什么我在這里問這個問題。

我想要的是保存包含命名的多值屬性(=帳戶屬性)的實體(帳戶)。

我已經使用了3種實體類型: Account -> @OneToMany -> AccountAttribute -> @OneToMany -> AccountAttributeValue

但是使用我自己的Classes包裝本機Java類型對我來說似乎有些愚蠢 克隆Map <String,String>示例我希望有類似的東西

@Entity
public class Account {

    @Id @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name="key")
    private Long key;

    @ElementCollection(fetch=FetchType.EAGER)
    @JoinTable(name = "Attribute",
            joinColumns = @JoinColumn(name = "fkAccount"))
    @MapKeyColumn(name = "name")
    // next line is working for Map<String, String>, but not here!
    @Column(name = "value")  
    private Map<String, Set<String>> attributes = new HashMap<String, Set<String>>();

    // ... omitting: constructor, getters, setters, toString()

}

哪能給我
Initial SessionFactory creation failed: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: Attribute, for columns:[org.hibernate.mapping.Column(attributes)]

作為DB布局我創建了2個表。 - 表Account只有一個鍵將外鍵指向 - 表Attribute ,每行包含命名值。

例如,對於多值屬性,我認為它包含2行具有相同的fkAccountname但不同的value - 是的,我可能已經規范化甚至更多,但我想在可接受的時間內讀取我的數據:-)

CREATE  TABLE IF NOT EXISTS `foo`.`Account` (
  `key` INT NOT NULL AUTO_INCREMENT ,
  ...

CREATE  TABLE IF NOT EXISTS `foo`.`Attribute` (
  `fkAccount` INT NOT NULL ,
  `name` VARCHAR(45) NOT NULL ,
  `value` VARCHAR(45) NOT NULL 
  ...

任何提示或備用數據庫布局提議表示贊賞。

編輯 - 已解決
湯姆的解決方案(據我所知)為我工作謝謝你們,一天的體驗,解決方案!

我在上面提到的表格布局現在適用於這些類。

@Entity
public class Account {
    /* ... omitting "key", see as above */

    /* NEW: now @CollectionTable 
            replaces @JoinTable / @MapKeyColumn / @Column  from above
    */
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name="AccountAttribute",
                     joinColumns=@JoinColumn(name="fkAccount"))
    private Set<AccountAttribute> attributes = null;

    // ... omitting: constructor, getters, setters, toString()
}

和新的

    @Embeddable
    public class AccountAttribute {

        @Column(name="attributeName")
        private String attributeName = null;

        @Column(name="attributeValue")
        private String attributeValue = null;

        // ... omitting: constructor, getters, setters, toString()
    }

JPA不會為您提供任何方式來映射任何集合的集合。 您可以映射基元,對實體的引用,嵌入式以及任何前述事物的集合。

那里的集合意味着集合,列表或地圖; 這里沒有多圖類型可以幫到你。

因此,遺憾的是沒有辦法准確映射您想要映射的結構。

我認為你最接近的可能是定義一個包含名稱和值的可嵌入類Attribute ,然后映射Set<Attribute> 然后,您可以將其轉換為代碼中的Map<String, Set<String>>

很遺憾沒有辦法做到這一點。 我認為JPA規范的作者要么沒有想到它,要么認為這是一個不起眼的案例,它不值得處理。

有兩種方法可以在數據庫中對此進行建模,它可以歸結為您需要多少個表。 如果你想要三個,那么你的工作方式基本上是正確的,盡管你可以將它修剪為兩個實體( AccountAccountAttribute ),其中AccountAttribute包含一組值。

您無法使用三個表和一個Account實體對其進行建模,因為您沒有足夠的標識符。 VALUE表必須有一個由帳戶ID和某種屬性鍵組成的復合鍵,您的表必須如下所示:

ACCOUNT (id, ...)
ACCOUNT_ATTRIBUTE(account_id, account_attribute_id, ...)
ACCOUNT_ATTRIBUTE_VALUE(account_id, account_attribute_id, value, ...)

如果AccountAttribute是一個實體,那么它有一個ID。 如果沒有,它沒有,那么你如何鍵入ACCOUNT_ATTRIBUTE_VALUE表?

JPA規范證實了這一點,正如其他答案中所提到的那樣。

現在,您可以在兩個只有一個Account實體的表中執行此操作,方法是將該Set轉換為某個序列化形式,並將其保存為二進制,XML或其他任何形式。 不確定這是否值得你付出努力,但你勾勒出的列( value varchar(45) )幾乎肯定不夠長。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM