1

Java Persistence を使用して基本的な EAV モデルを作成しました (ユーザーは実行時に動的に新しい属性を時々作成するため、EAV または同様のものが必要です)。

最近、適切に解決できない問題に遭遇しました (私が好まない回避策のみ、以下の回避策、 DataEntity#buildIndex() を参照)。

問題は次のとおりです。DataEntity は特定の DataEntityType のものです。この DataEntityType には、プロパティ (Type、Validators、Length など) を定義する多くの PropertyType があります。
DataEntity には、DataEntity の DataEntityType が持つ PropertyType ごとに 1 つずつ、多くのプロパティがあります。

問題は次のとおりです (ここでコメント付きのコード形式で説明していることについては、以下のクラス DataEntity も参照してください)。これらのプロパティを次のようにマップしたいと思います。

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

等々。

@EmbeddedId を使用してこれを実行しようとしましたが、これにより、Entity.id および Property.id であるこの「12-16」のように見える PK としての文字列を持つ列につながります。

これを避けて、現在のプロパティ テーブルを使用したいと思います。

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

注意: オブジェクトとしてロードされたときにプロパティが両方への参照を持っているため、entity_id と property_type_id は既にここにあります!

私が考えていた別のアイデアは、@PostLoad を使用して実行する CriteriaQuery を作成することでしたが、基本的には現在行っていることと同じであるため、その前に入力を求めたいと思いました...また、私はそうではありませんより複雑なクエリを実行してマップのパフォーマンスにデータを入力することが賢明である場合でも、データをロードして送信する必要があるため、データベースではなくアプリケーションでこれを行う方が良いかもしれません...

ご協力ありがとうございました。

以下のコード:

@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()
    {

    }
}
4

0 に答える 0