Java持久性使用来自两个不同类的Id填充地图

时间:2013-06-07 10:38:07

标签: java hibernate persistence composite-key

我使用Java Persistence创建了一个基本的EAV模型(需要EAV或类似功能,因为用户将不时在运行时动态创建新属性)。

我最近遇到了一个我无法正确解决的问题(只有我不喜欢的解决方法,下面的解决方法,请参阅DataEntity#buildIndex())

问题如下: DataEntity属于某个DataEntityType,此DataEntityType具有许多PropertyType,用于定义属性(Type,Validators,Length等)。
DataEntity有许多属性,每个属性对应DataEntity的DataEntityType。

问题如下:(另请参阅下面的Class DataEntity,我在这里以代码形式描述了注释) 我想映射这样的属性:

Map<PropertyType, PropertyString> strings;
Map<PropertyType, PropertyInteger> integers;

等等。

我尝试使用@EmbeddedId执行此操作,但这会导致一个字符串为PK的列看起来像“12-16”,这是Entity.id和Property.id

我想避免这种情况,并使用现在的属性表:

property_string(id, entity_id, property_type_id, value)
property_integer(id, entity_id, property_type_id, value)

注意:entity_id和property_type_id已经在这里,因为一个Property在作为Object加载时都有对它们的引用!

我想到的另一个想法是用@PostLoad编写一个CriteriaQuery运行但是我想在我做之前首先要求输入一些,因为这基本上和我现在做的一样......而且我我甚至不确定是否明智地做一个更复杂的查询以明智地填充Map的性能...也许在应用程序而不是数据库中执行此操作会更好,因为数据必须以任何方式加载和传输...

感谢您的帮助。

以下代码:

@Entity
public class DataEntity
{

    @Getter
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected long                               id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "entity_type")
    protected DataEntityType                     type;

    @OneToMany(mappedBy = "entity", cascade = CascadeType.ALL)
    protected List<PropertyInteger>              integers = new ArrayList<PropertyInteger>();

    @OneToMany(mappedBy = "entity", cascade = CascadeType.ALL)
    protected List<PropertyString>               strings  = new ArrayList<PropertyString>();

    // CURRENT SOLUTION; CREATE THOSE AFTER LOADING (SEE method "indexData()" below)
    // WHAT IM TRYING TO DO IS LOAD THESE MAPS DIRECTLY WITHOUT THE MIDDLE STEP
    @Transient
    protected Map<PropertyType, PropertyInteger> mappedIntegers = new HashMap<PropertyType,PropertyInteger>();

    @Transient
    protected Map<PropertyType, PropertyString>  mappedStrings = new HashMap<PropertyType, PropertyString>();

    protected DataEntity(DataEntityType t)
    {
        type = t;
    }

    @Deprecated
    protected DataEntity()
    {
    }

    @PostLoad
    private void indexData()
    {
        indexData(integers, mappedIntegers);
        indexData(strings, mappedStrings);
    }

    private <T extends Property<?>> void indexData(List<T> list, Map<PropertyType, T> map)
    {
        map.clear();
        for (T p : list)
        {
            map.put(p.getType(), p);
        }
    }

    // methods to deal with property creation/modification/etc skipped since they have no influence
    // on the mappings
}

@Entity
public class DataEntityType
{

    @Getter
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Getter
    @OneToMany(mappedBy = "entityType", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<PropertyType> propertyTypes = new ArrayList<PropertyType>();

    protected DataEntityType()
    {
    }
}

@MappedSuperclass
public class Property<T>
{

    @Getter
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long         id;

    @Getter
    @ManyToOne(cascade = CascadeType.ALL)
    private PropertyType type;

    @Getter
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "entity", nullable = false)
    private DataEntity   entity;

    @Getter
    @Setter
    @Column(name = "value", nullable = true)
    private T            value;

    protected Property(DataEntity e, PropertyType t, T v)
    {
        entity = e;
        type = t;
        value = v;
    }

    @Deprecated
    protected Property()
    {
    }
}

@Entity
public class PropertyType
{

    @Getter
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long   id;

    @Column(name = "code", nullable = false)
    private String code;

    @ManyToOne
    @JoinColumn(name = "entity_type")
    private DataEntityType entityType;

    protected PropertyType(DataEntityType t, String c)
    {
        entityType = t;
        code = c;
    }

    @Deprecated
    protected PropertyType()
    {
    }
}

@Entity
public class PropertyString extends Property<String>
{

    public PropertyString(PropertyType t, DataEntity e, String v)
    {
        super(e, t, v);
    }

    @Deprecated
    protected PropertyString()
    {

    }
}

@Entity
public class PropertyInteger extends Property<Integer>
{

    public PropertyInteger(PropertyType t, DataEntity e, Integer v)
    {
        super(e, t, v);
    }

    @Deprecated
    protected PropertyInteger()
    {

    }
}

0 个答案:

没有答案