0

我目前正在使用良好的面向对象原则,并且休眠时,我有这个 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);
    }


}

所以我希望能够动态地创建一个具有此属性的表,即 My Enum:

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;
    }
}

我有这个休眠映射,但是正如您所看到的,每次更新字段时都需要更新它,我需要一个通用映射,这样当我更改/添加属性时,注释或 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>
4

1 回答 1

2

Marin Fowler 网站上的UserDefinedField可能是探索这个问题的一般答案的完美起点。

至于 Hibernate:它实际上是为将表静态绑定到对象而设计的,如果您在运行时更改架构,您可能会遇到重大问题。不过,您可以实施以下解决方案:

  • 序列化 LOB(您将 Map 序列化为二进制字段或 - 使用 JSON/XML - 文本字段)。这是一种对半方法 - 一半表格/正常形式/SQL,一半非 SQL。因此,如果这种方法很有吸引力,您可能需要考虑使用 NoSQL 数据库,如下所述
  • 属性表,您的自定义属性存储在连接到主表的键值对表中。这可以在 Hibernate 中使用Indexed Collections进行映射(请参阅第 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;
    
    }
    
  • Pre-defined custom-fields, where you start with a really wide table with loads of unused columns. In this implementation you end up defining a mapping between your arbitrary property names and the pre-defined column names (getString1(), getString10(), etc)

However, a much better solution for you may be to use a NoSQL database - specifically a document-based one. These allow you to store and retrieve arbitrary data-structures (maps and lists). Interestingly, using such an approach makes binding to the data store significantly easier.

MongoDB or Redis (Java bindings at Jedis) are examples.

于 2013-08-05T10:11:08.273 回答