【问题标题】:Hibernate custom foreign keyHibernate 自定义外键
【发布时间】:2020-05-02 06:45:28
【问题描述】:

我需要使用一个数据库,其中包含一些自定义外键的 2 个表。它将在特定条件下引用一个字段,否则将引用另一个字段。

如何使用 Hibernate 对此进行注释?

这是表格。

---------------------------                      ---------------------------
|         customer        |                      |         address         |
---------------------------                      ---------------------------
| - id                    |                      | - address_code          |
| address_code            |                      | - customer_id           |
| primary_language_code   |                      | - language_code         |
| secondary_language_code |                      | ...                     |
| ...                     |                      |                         |
---------------------------                      ---------------------------

- 开头的字段是(部分)主键。 外键如下:

customer join address on 
    (customer.id = address.customer_id
    and customer.address_code = address.address_code
    and (case when customer.primary_language_code <= 2 
              then customer.primary_language_code 
              else customer.secondary_language_code
         end) = address.COD_LAN)

以下是模型:

@Getter              \
@Setter              |   //lombok
@NoArgsConstructor   /
@Entity
@Table(name = "customer")
public class Customer{

    @Id
    @Column(name="id")
    private int id;

    @Column(name="primary_language_code")
    private int primaryLanguageCode;

    @Column(name="secondary_language_code")
    private int secondaryLanguageCode;

    ?
    private Address address;
}

@Getter              \
@Setter              |   //lombok
@NoArgsConstructor   /
@Entity
@Table(name = "address")
public class Address {

    @EmbeddedId
    private AddressId id;
}

@Getter              \
@Setter              |   //lombok
@NoArgsConstructor   /
@Embeddable
public class AddressId implements Serializable, Comparable<AddressId> {

    @Column(name = "customer_id")
    private int customerId;

    @NonNull
    @Column(name = "address_code")
    private String addressCode;

    ?
    private int languageCode;
}

编辑:

  • 我尝试使用计算字段并从该字段映射。问题:如何映射这个计算字段?
  • 我尝试使用 @Where 子句,但模型字段名称连接到 sql 查询字段 customer0_.address_primary_language_code
@Where(clause = "(customer.primary_language_code <= 2 then customer.primary_language_code else customer.secondary_language_code end) = address.COD_LAN)")
  • 我也尝试了其他几件事,但都没有成功。

【问题讨论】:

  • 在这种情况下,您应该使用注释 oneToOne 映射。示例示例baeldung.com/jpa-one-to-one
  • 还要使用addressCode加入列
  • 我的问题不是如何使用简单的一对一映射。我的问题是列将根据条件映射列primary_language_codesecondary_language_code。这个条件怎么写?
  • 我的建议是按原样加载它并在模型对象中管理条件。
  • 这是我目前正在做的解决方法,因为找不到我的问题的解决方案。但是,我对此感觉不太好,因为我正在更改的代码(模型)被其他几个应用程序使用:/

标签: java hibernate


【解决方案1】:

所以,我发现了一些使用 sql 注入的令人毛骨悚然的 hack,它解决了我的问题,但在某些情况下可能容易出现错误。

如果仅在primary_language 上加入,代码将是这样的:

@OneToOne
@JoinColumns({@JoinColumn(name = "id", referencedColumnName = "customer_id"),
              @JoinColumn(name = "primary_language_code", referencedColumnName = "language_code"),
              @JoinColumn(name = "address_code", referencedColumnName = "address_code")})
private Address address;
@Column(name = "language_code", nullable = false)
private int languageCode;

Hibernate 会生成这样的查询:

select customer0_.id as ...,
       customer0_.primary_language_code as ...,
       customer0_.secondary_language_code as ...,
       customer0_.address_code as ...

思路是改变name值注入sql代码:

@OneToOne
@JoinColumns({@JoinColumn(name = "id", referencedColumnName = "customer_id"),
              @JoinColumn(name = "id, case when customer.primary_language_code <= 2 " +
                                          "then customer.primary_language_code " +
                                          "else customer.secondary_language_code end",
                          referencedColumnName = "language_code"),
              @JoinColumn(name = "address_code", referencedColumnName = "address_code")})
private Address address;

生成的 sql 查询将如下所示:

select customer0_.id as ...,
       customer0_.primary_language_code as ...,
       customer0_.secondary_language_code as ...,
       customer0_.id,                                    <--- sql injection here
       case
           when customer.primary_language_code <= 2 then customer.primary_language_code 
           else customer.secondary_language_code 
       end as ...,
       customer0_.address_code as ...

除非您需要在客户表中加入的另一个表中有primary_language 或secondary_language,否则这将起作用。

我很高兴为这个问题找到更好的解决方案,因为我真的不敢在生产中使用它。

【讨论】:

    猜你喜欢
    • 2011-10-12
    • 2017-05-14
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    • 2021-12-12
    相关资源
    最近更新 更多