【问题标题】:Java EE/JPA: Applying key-value table techniquesJava EE/JPA:应用键值表技术
【发布时间】:2015-04-21 21:26:42
【问题描述】:

使用 JPA,我意识到我有动态增长的实体,即一个实体的属性数量可能会有所不同。知道有一些基于键值表的解决方案,我有兴趣了解有关如何将这些技术应用于 JPA (JPQL) 的更多信息。

示例结构如下所示:

REF-ID       KEY         VALUE
1000         name        foo
1000         category    basic
1001         name        bar
1001         category    advanced
1001         descr       none
--------------------|------------
     PRIMARY        |

问题是这种表可能会大幅增长,达到数百万条记录。 下一个问题是如何映射查询,例如

SELECT name, category, descr
FROM KEYSTORE 
WHERE id=1000;

... descr 是否可用

在使用 JPA 时,我是否在这里遗漏了任何概念来满足此要求,或者我是否必须在此处使用其他技术?性能怎么样?

【问题讨论】:

    标签: database jakarta-ee jpa


    【解决方案1】:

    数百万条记录是数据库的正常用例。 请记住在您的 ref-id 上有索引(如果它还不是主键)。您也可以通过 ref-id 进行表分区(包括 MySQL 在内的几乎所有数据库都支持),以提高性能,但它是数据库优化而不是 JPA 优化。

    至于 JPA,可以映射 Map 值 如果您的属性将表示为字符串(名称、值),那么只需

    class ComplexEntity {
     @ElementCollection
     @CollectionTable....
     Map<String, String> attributes;
    }
    ....
    String descr = entity.getAttributes.get("descr")
    

    Storing a Map<String,String> using JPA

    或者您可以定义新的实体:属性并映射到它:

    @Entity
    class Attribute {
        @ID
        Long id;
        @Column(name="name")
        String name;
        @Column(name="pvalue")
        String value;
    }
    
    class ComplexEntity {
    @OneToMany(cascade=CascadeType.ALL,orphanRemoval = true)
    @MapKey(name="name") 
    @JoinTable(name = "ATTR_TABLE")
    private Map<String,Attribute> attributes;
    

    通过这种映射,属性映射键可以是其值的实际字段(属性由 Attribute.name 值索引)。

    要小心,不要调用列/对象字段 KEY、VALUE、PARAM 或任何其他潜在的 sql/jpql 关键字,因为它通常在复杂的查询中不起作用,但很难找到原因(我很难找到)。

    至于查询,正常的 JPQL 工作, 所以你只需抓住你复杂的实体,然后从属性映射中访问感兴趣的值。 或者你查询他们

    SELECT a.value FROM ComplexEntity c INNER JOIN c.attributes a WHERE c.id = :id AND a.name IN :names
    

    【讨论】:

    • 非常感谢您的帮助。但是桌子的旋转呢?我的意思是看我的查询。当我需要时,例如单个语句中的实体名称、描述、类别?
    • 我的答案中的最后一个选择会重新检索它们,就好像您想知道哪个是而不是您必须使用 AS 和 UNION 拆分选择(可能)。但它是 JPA,它是关于对象的。你想用未知数量的属性对你的对象建模,所以你这样做了,但是,你应该只获取具有所有属性的对象并使用你需要的那些,而不是单独访问属性。如果它只是具有许多字段的对象,这就是你会做的(如果你使用的是 java 和 JPA,你不应该过多考虑底层数据库作为特定的选择)
    • 嗯,但假设我有 10k 个对象,每个对象引用 1k 个(键、值)对。现在我想创建一个动态表,其中仅包含 1k 个键中的 10 个作为列。使用 Map 我会选择所有实体,从数据库中获取所有地图(内存中有 100 亿个条目)并手动将我的查询“翻译”为地图条目的编程选择/检查,对吗?
    • 使用属性实体方式(所以没有简单的字符串映射),您按照上述设置(WHERE a.name IN :names_of_interest)进行选择,每个属性都有其名称和值属性,因此您知道它们代表什么,您可以构建您的动态表(在属性上添加 ManyToOne 到 ComplexEntity),以了解如果您检索多个时它们属于哪个。该地图是惰性的,因此在需要之前不会阅读。最后,如果您不关心 CoplexEntity 的对象视图,则根本不要在 JPA 中映射它并手动管理表。
    • @D-Klotz,c.id 是 CompleEntity 的 id,所有 JPA 实体都必须有一个 id,上面的示例中没有包含它,但是 ComplexEntity 类也应该声明它(类 ComplexEntity { '@ID' id, '@OneToMany' ...)。在此 id 的属性值上使用 OneToMany 注释来引用 ATTR_TABLE。
    猜你喜欢
    • 2011-08-16
    • 1970-01-01
    • 2012-12-08
    • 2011-03-18
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    • 2013-03-30
    • 1970-01-01
    相关资源
    最近更新 更多