我目前正在运行良好的面向对象原则,而hibernate,我有这个POJO,其中属性将被动态填充。这是我为良好的面向对象设计而阅读的设计模式,其中很容易在不破坏应用程序的情况下向特定对象添加属性。 我的问题是,当你的属性被认为是动态的时,如何将其映射到表格,我使用枚举来限制地图的键值对,但理想情况下它仍然可以增长。我只使用内存数据库(h2),我不打算将代码用于生产用途。这仅用于学习目的。见下面的代码:
public class Transaction {
private static Map<Object, Object> properties;
public Transaction(){
if(null != properties)
properties = new LinkedHashMap<Object, Object>();
}
public Transaction(Map<Object, Object> properties){
if(null != properties)
setProperties(properties);
}
public void setProperties(Map<Object, Object> prop){
properties = prop;
}
public void setProperties(Properties property, String value){
properties.put(property, value);
}
public Map<Object, Object> getProperties(){
return properties;
}
public String getProperties(Properties property){
return (String) properties.get(property);
}
}
所以我希望能够动态地创建一个具有此属性的表, 我的枚举:
public enum Properties {
Entry("Entry"), Id("Entry_ID"), Name("Name"), Credit("Credit");
private final String description;
private Properties(final String description){
this.description = description;
}
@Override
public String toString(){
return description;
}
}
我有这个hibernate映射,但你可以看到每次更新字段时都需要更新,我需要一个通用的映射,以便在我更改/添加属性时,注释或者xml没问题,见下文:
<class name="Transaction" table="TRANSACTION">
<id name="id" column="ENTRY_ID">
<generator class="increment"/>
</id>
<property name="name"/>
<property name="credit" type="boolean" column="IS_CREDIT"/>
</class>
答案 0 :(得分:2)
UserDefinedField可能是探索这个问题的一般答案的完美起点。
至于Hibernate:它实际上是为将表静态绑定到对象而设计的,如果在运行时更改模式,则可能会遇到严重问题。但是,您可以实现以下解决方案:
属性表,其中您的自定义属性存储在连接到主表的键值对表中。这可以使用Indexed Collections在Hibernate中进行映射(请参阅第7.2.2.2节地图),您最终会得到与您的问题类似的内容:
@Entity
public class Transaction {
@Id @GeneratedValue public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
private Integer id;
// ... snip ...
@OneToMany(mappedBy="transaction")
@MapKey(name="name")
public Map<String, String> getProperties(){
return properties;
}
public void setProperties(Map<String, String> prop){
properties = prop;
}
private Map<String, String> properties; // NB: Type has to be <String, String> because the column name is a String and you have defined the property value to be a String.
public void setProperty(Properties property, String value){
properties.put(property, value);
}
public String getProperty(String name){
return (String) properties.get(property);
}
}
@Entity
public class Property {
@Id @GeneratedValue public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
private Integer id;
@ManyToOne
public Transaction getTransaction() { return transaction; }
public void setTransaction(Transaction transaction) { this.transaction = transaction; }
private Transaction transaction;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
private String name;
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
private String description;
}
预定义的自定义字段,您可以从一个非常宽的表开始,其中包含大量未使用的列。在此实现中,您最终定义了任意属性名称与预定义列名称之间的映射(getString1()
,getString10()
等)
但是,更好的解决方案可能是使用NoSQL数据库 - 特别是基于文档的数据库。这些允许您存储和检索任意数据结构(地图和列表)。有趣的是,使用这种方法可以更轻松地绑定到数据存储 。