[英]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行具有相同的fkAccount
和name
但不同的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規范的作者要么沒有想到它,要么認為這是一個不起眼的案例,它不值得處理。
有兩種方法可以在數據庫中對此進行建模,它可以歸結為您需要多少個表。 如果你想要三個,那么你的工作方式基本上是正確的,盡管你可以將它修剪為兩個實體( Account
和AccountAttribute
),其中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.