【问题标题】:How do I reverse key value map types on one side of @ManyToMany JPA relationship如何在@ManyToMany JPA 关系的一侧反转键值映射类型
【发布时间】:2019-09-06 22:03:58
【问题描述】:

我需要关于 KeyStoreEntity 与其 3 个子实体 (KeyPairEntity, SecretKeyEntity, CertificateEntity) 之间的多对多关系的建议。我将在此示例中使用CertificateEntity,因为其他 2 遵循相同的模式/问题。我的扩展类BaseRdbmsEntity 是一个@MappedSuperclass,具有id、name 和description 属性。

我对双方的@ManyToMany 没有任何问题,并在KeystoreEntity 方面使用Map<String, CertificateEntity> 通过他们的别名获取证书,并在CertificateEntity 上使用Map<String, KeyStoreEntity> 来获取别名和相关的密钥库。

然后我意识到我把它搞砸了,因为证书很容易在不同的密钥库中具有相同的别名......因此CertificateEntity 映射键可能会发生冲突,并且一个值会在存储库查询期间清除存储在其中的后续值。

我需要将CertificateEntity 中映射属性的键/值类型反转为Map<KeyStoreEntity, String>。我不清楚我如何使用@MapKeyValue(我意识到这不存在)将别名作为映射中的值......而不是作为键。

我试图通过使用@JoinTable 注释来解决此问题,但我没有看到与@MapKeyColumn 等效的映射值侧。我想要的是KeyStoreEntity 作为键和String alias 作为值。

@Entity(name = "keystores")
@Table(name = "pki_keystores")
public class KeyStoreEntity extends BaseRdbmsSecurityEntity
{
    @MapKeyColumn(name="alias")
    @ManyToMany
    (
        fetch = FetchType.LAZY,
        cascade = {CascadeType.PERSIST, CascadeType.MERGE}
    )
    private Map<String, CertificateEntity> certificates;
    ...snip...
}

@Entity(name = "certificates")
@Table(name = "pki_certificates", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"issuerDn", "serialNumber"})
})
public class CertificateEntity extends BaseRdbmsSecurityEntity
{
    @MapKeyColumn(name="alias")
    @ManyToMany(
        fetch = FetchType.LAZY,
        cascade = {CascadeType.PERSIST, CascadeType.MERGE},
        mappedBy = "certificates",
        targetEntity = KeyStoreEntity.class
    )
    private Map<String, KeyStoreEntity> keystores;
    // Map type for above needs to be <KeyStoreEntity, String>
    ...snip...
}

我希望延迟获取可以在关系的CertificateEntity.keystores 一侧使用反转的 k/v。我的期望是我只需要为keystores 属性调整/添加注释到CertificateEntity

【问题讨论】:

    标签: java hibernate dictionary jpa mapkeyjoincolumn


    【解决方案1】:

    这是一个单向/双向关系多对多的示例。我希望您能轻松地将其调整为您的代码)这只是List 的简单示例。 Check out this question 也是如此

    @ManyToMany

    unidirectional:

    用户.java

    @Entity
    public class User {
    
        @Id
        @GeneratedValue
        @Column(name = "user_id")
        private long id;
    
        ...
    
        @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
        private List<Role> roles = new ArrayList<>();
    
        public void addRoles(Role role) {
            roles.add(role);
        }
    
        public void removeRoles(Role role) {
            roles.remove(role);
        }
    }
    
    

    角色.java

    @Entity
    public class Role {
    
        @Id
        @GeneratedValue
        @Column(name = "role_id")
        private int id;
    
        @Column(name = "role")
        private String role;
    }
    
    



    bidirectional:

    Trader.java:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Entity
    @ToString(exclude = "stockmarkets")
    @Table(name = "trader")
    public class Trader {
    
        @Id
        @GeneratedValue
        @Column(name = "trader_id")
        private Long id;
    
        @Column(name = "trader_name")
        private String traderName;
    
        @ManyToMany(fetch = FetchType.LAZY,
                cascade = {
                CascadeType.PERSIST,
                CascadeType.MERGE
        })
        @JoinTable(name = "TRADER_STOCKMARKET",
                joinColumns = { @JoinColumn(name = "trader_id") },
                inverseJoinColumns = { @JoinColumn(name = "stockmarket_id") })
        private List<Stockmarket> stockmarkets = new ArrayList<>();
    
    
        /*
        We need to add methods below to make everything work correctly
         */
    
        public void addStockmarket(Stockmarket stockmarket) {
            stockmarkets.add(stockmarket);
            stockmarket.getTraders().add(this);
        }
    
        public void removeStockmarket(Stockmarket stockmarket) {
            stockmarkets.remove(stockmarket);
            stockmarket.getTraders().remove(this);
        }
    
    }
    
    

    Stockmarket.java

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Entity
    @ToString(exclude = "traders")
    @Table(name = "stockmarket")
    public class Stockmarket{
    
        @Id
        @GeneratedValue
        @Column(name = "stockmarket_id")
        private Long id;
    
        @Column(name = "stockmarket_name")
        private String stockmarketName;
    
        @ManyToMany(mappedBy="stockmarkets")
        private List<Trader> traders = new ArrayList<>();
    
        /*
        We need to add methods below to make everything work correctly
         */
    
        public void addTrader(Trader trader) {
            traders.add(trader);
            trader.getStockmarkets().add(this);
        }
    
        public void removeTrader(Trader trader) {
            traders.remove(trader);
            trader.getStockmarkets().remove(this);
        }
    
    }
    
    

    【讨论】:

    • 你好。感谢您提供信息,但我不明白这对我的情况有何帮助,我需要 Map.Entry 使用实体作为键和别名作为值。有一些注释可以让您指定映射键,但不清楚如何为 map.entry 元组的值部分获取 String:alias。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多