使用Hibernate Core 4.1.7,JPA注释,java 1.7
关于Map< String,Entity>的例子很容易。读取Hibernate doc on collections或Map< String,String> here (stackoverflow)
很难找到关于Map<String, Set<String>>
的例子(或者甚至是Map&lt; String,Map&lt; String,String&gt;&gt;只是为了好奇关于菊花chaning)为什么我在这里提出这个问题。
我想要的只是保存包含命名的多值属性(=帐户属性)的实体(帐户)。
我已经使用了3种实体类型:Account -> @OneToMany -> AccountAttribute -> @OneToMany -> AccountAttributeValue
但是使用我自己的类包装本机Java类型对我来说似乎有点愚蠢。克隆Map&lt; String,String&gt;例如我想要像
这样的东西@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)]
作为数据库布局,我创建了2个表。
- 表Account
只有一个指向外键的键
- 表Attribute
在每行中包含命名值。
E.g。对于多值属性我认为它包含 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
...
任何提示或备用数据库布局提案均受到赞赏。
编辑 - 已解决
汤姆的解决方案(据我所知)为我工作
谢谢你们,1天的体验,解决方案!
我在上面提到的表格布局现在适用于这些类。
@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()
}
答案 0 :(得分:3)
JPA没有为您提供任何方式来映射任何集合的集合。您可以映射基元,对实体的引用,嵌入式以及任何前述事物的集合。
集合表示集合,列表或映射;这里没有多图类型可以帮助你。
因此,遗憾的是没有办法准确映射你想要映射的结构。
我认为你最接近的可能是定义一个包含名称和值的可嵌入类Attribute
,然后映射Set<Attribute>
。然后,您可以将其转换为代码中的Map<String, Set<String>>
。
遗憾的是,没有办法做到这一点。我认为JPA规范的作者要么没有想到它,要么认为这是一个不起眼的案例,不值得处理。
答案 1 :(得分:1)
有两种方法可以在数据库中对此进行建模,这取决于您需要多少个表。如果您想要三个,那么您的工作方式基本上是正确的,尽管您可以将其修剪为两个实体(Account
和AccountAttribute
),其中AccountAttribute
包含一组值。
您无法使用三个表和一个帐户实体对其进行建模,因为您没有足够的标识符。 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规范得到证实,如other answer中所述。
现在,您可以在只有Account
实体的两个表中执行此操作,方法是将该Set压缩为某个序列化形式并将其保存为二进制,XML或其他任何形式。不确定这是否值得你付出努力,但你勾勒出的专栏(value varchar(45)
)几乎肯定不够长。