【问题标题】:JPA OneToOne Mapping On Partial Primary Keys Column部分主键列上的 JPA OneToOne 映射
【发布时间】:2021-03-15 09:54:41
【问题描述】:

我有两个表,如下所述:

+-------------------+        +------------------------+        
| TB_CONFIG         |        | TB_CONFIG_LANG         |        
+-------------------+        +------------------------+        
| Customer_Id  (PK) |        | Product_Id         (PK)|        
| Company_Id   (PK) |        | Config_Id          (PK)|        
| Product_Id   (PK) |        | Language_Id        (PK)|        
| Config_Id    (PK) |        | Config_Description     |        
| Config_Value      |        | Config_Hint            |        
+-------------------+        | Config_Help            |   
                             +------------------------+  

TB_CONFIG 数据是关于由指定的“客户”和“公司”在我们拥有的“产品(解决方案)”上设置的“配置”。

TB_CONFIG_LANG 存储有关各种语言的所有配置的描述、提示和帮助的数据,例如“EN_US”、“PT_BR”等。

我们总是将语言作为参数传递给将用于加载数据的JPQL,但我无法实现映射此连接的“正确方式”...

实际上,这些表映射如下:

TB_CONFIG_LANG 主键

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Embeddable
@MappedSuperclass
public class PkConfigurationLang implements Serializable {

    @Column(name = "PRODUCT_ID")
    @EqualsAndHashCode.Include
    private int productId;

    @Column(name = "CONFIG_ID")
    @EqualsAndHashCode.Include
    private String configId;

    @Column(name = "LANGUAGE_ID")
    @EqualsAndHashCode.Include
    private String languageId;

}

TB_CONFIG_LANG 表

@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Entity
@Table(schema = "CLOUD_CATALOG", name = "TB_CONFIG_LANG")
@Cache(region = "oConfigurationsCache", usage = CacheConcurrencyStrategy.READ_WRITE)
public class ConfigurationLanguage {

    @EmbeddedId
    private PkConfigurationLang id;

    @Column(name = "CONFIG_DESCRIPTION")
    private String name;

    @Column(name = "CONFIG_HINT")
    private String description;

    @Column(name = "CONFIG_HELP")
    private String help;

}

TB_CONFIG 主键

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Embeddable
@MappedSuperclass
public class PkConfiguration implements Serializable {

    @Column(name = "CUSTOMER_ID")
    @EqualsAndHashCode.Include
    private int customerId;

    @Column(name = "COMPANY_ID")
    @EqualsAndHashCode.Include
    private int companyId;

    @Column(name = "PRODUCT_ID")
    @EqualsAndHashCode.Include
    private int productId;    
    
    @Column(name = "CONFIG_ID")
    @EqualsAndHashCode.Include
    private String configId;

}

TB_CONFIG 表

@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Entity
@Table(schema = "CLOUD_CATALOG", name = "TB_CONFIG")
@Cache(region = "oConfigurationsCache", usage = CacheConcurrencyStrategy.READ_WRITE)
public class Configuration {

    @EmbeddedId
    private PkConfiguration id;

    @Column(name = "CONFIG_VALUE")
    private String configValue;

}

我的第一次尝试是映射@OneToOne 关系一个Configuration 类,如下所示:

具有 OneToOne 关系的 TB_CONFIG 表

@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Entity
@Table(schema = "CLOUD_CATALOG", name = "TB_CONFIG")
@Cache(region = "oConfigurationsCache", usage = CacheConcurrencyStrategy.READ_WRITE)
public class Configuration {

    @EmbeddedId
    private PkConfiguration id;

    @Column(name = "CONFIG_VALUE")
    private String configValue;

    @OneToOne
    @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "PRODUCT_ID", insertable = false, updatable = false)
    @JoinColumn(name = "CONFIG_ID", referencedColumnName = "CONFIG_ID", insertable = false, updatable = false)
    private ConfigurationLanguage language;

}

然后像这样写一个 JPQL:

TypedQuery<ConfigurationCompany> query = manager.createQuery("select c from ConfigurationCompany c " +
        "join c.language l " +
        "where c.id.customerId = :customerId " +
        "and c.id.companyId = :companyId " +
        "and c.id.productId = :productId " +
        "and c.id.configId = :configId " +
        "and l.id.languageId = :languageId", ConfigurationCompany.class);

但我在尝试运行应用程序时收到以下异常:

org.springframework.orm.jpa.JpaSystemException: referencedColumnNames(PRODUCT_ID, CONFIG_ID) of com.mycompany.api.configuration.domain.model.ConfigurationCompany.language referencing com.mycompany.api.configuration.domain.model.ConfigurationLanguage not mapped to a single property; nested exception is org.hibernate.AnnotationException: referencedColumnNames(PRODUCT_ID, CONFIG_NAME) of com.mycompany.api.configuration.domain.model.ConfigurationCompany.language referencing com.mycompany.api.configuration.domain.model.ConfigurationLanguage not mapped to a single property

我认为这是因为我在创建 @OneToOne 映射时没有引用 Language_Id 列...

所以,问题是: 这是实现这种关系的正确方法吗?如果是,我错过了什么? 如果没有,我该如何正确配置此映射?

提示: 我无法更改数据库架构。

非常感谢!

【问题讨论】:

  • TB_CONFIG_LANG 没有列 CONFIG_NAME 但您在 @JoinColumn(name = "CONFIG_NAME", referenc... 中使用它
  • @DirkDeyne,对不起...写问题时出错了...正确的名称是 CONFIG_ID

标签: hibernate jpa spring-data-jpa hibernate-mapping one-to-one


【解决方案1】:

像这样的一对一映射是 Hibernate 不支持的 AFAIK。除此之外,这样做也不安全,除非您为TB_CONFIG(PRODUCT_ID, CONFIG_ID)TB_CONFIG_LANG(PRODUCT_ID, CONFIG_ID) 定义了唯一键。像这样使用@OneToMany 关联有什么问题:

@OneToMany
@JoinColumn(name = "PRODUCT_ID", referencedColumnName = "PRODUCT_ID", insertable = false, updatable = false)
@JoinColumn(name = "CONFIG_ID", referencedColumnName = "CONFIG_ID", insertable = false, updatable = false)
private Set<ConfigurationLanguage> languages;

这样,您只需要TB_CONFIG_LANG(PRODUCT_ID, CONFIG_ID) 的唯一键。为了避免这种情况,您需要使用地图:

@OneToMany
@MapKeyColumn(name = "LANGUAGE_ID")
@JoinColumn(name = "PRODUCT_ID", referencedColumnName = "PRODUCT_ID", insertable = false, updatable = false)
@JoinColumn(name = "CONFIG_ID", referencedColumnName = "CONFIG_ID", insertable = false, updatable = false)
private Map<String, ConfigurationLanguage> languages;

但请注意,从数据库的角度来看,这仍然不安全。外键必须始终引用唯一键。因此,要么将Company_IdCustomer_Id 也放入TB_CONFIG_LANG,要么从TB_CONFIG 的主键中删除这两个

【讨论】:

  • 你好@Christian,非常感谢!那是我尝试过的方法之一,但有同样的错误。唯一有效的是从 PK 中删除 LANGUAGE_ID 列,但我认为这不是正确的方法,因为模型没有反映数据库中的内容......
  • 你得到什么错误?我在许多项目中都使用了类似的方法,它对我来说效果很好
  • 我收到错误:引用 TB_CONFIG 的 TB_CONFIG_LANG 的 referencedColumnNames(PRODUCT_ID, CONFIG_ID) 未映射到单个属性
猜你喜欢
  • 2020-03-18
  • 2013-03-25
  • 2014-10-12
  • 2010-10-14
  • 2014-05-17
  • 2015-03-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
相关资源
最近更新 更多