为什么 JPA 选择 String 作为 JoinColumn 而不管键类型如何?

发布于 2024-09-29 03:17:03 字数 2460 浏览 1 评论 0原文

使用 EclipseLink JPA2 实现(不确定它是否与 Hibernate 实现相同)

我有一个简单的结构,其中组织实体具有合同。这是我从 postgres 导出来创建组织的 sql

CREATE TABLE organization (
    key bigint NOT NULL,
    version integer
);

如果我像这样指定组织的合同方:

@ManyToOne( optional=false )
@JoinColumn( name="organization_key", referencedColumnName="key" )
private Organization organization;

然后转储我得到的架构。

CREATE TABLE contract ( 
    key bigint NOT NULL, 
    version integer, 
    organization_key character varying(255), 
);

对于我来说,它使用字符变化(255)字段来引用组织密钥是没有意义的。我知道我可以使用 columnDefinition 如下:

@ManyToOne( optional=false )
@JoinColumn( name="organization_key", referencedColumnName="key", columnDefinition="bigint NOT NULL" )
private Organization organization;

获取 bigint 类型而不是字符类型。

我期望它获得正确的列类型是不现实的吗?是我用错了,还是我有错误的期望?我是否每次都必须使用columnDefinition?

更新: 这是来自组织实体的相关信息

@Entity
@Table( name = "organization" )
@SequenceGenerator( name = "ORGANIZATION_SEQ_GEN", sequenceName = "ORGANIZATION_SEQUENCE" )
public class Organization
        implements DataObject<Long>
{

    /**
     * key for this instance. Should be managed by JPA provider.
     */
    @Id
    @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "ORGANIZATION_SEQ_GEN" )
    private Long key;

    /**
     * JPA version column
     */
    @Version
    protected int version;

    /**
     * All contracts for this organization
     */
    @OneToMany(mappedBy="organization" )
    @OrderBy( "endDate DESC" )
    private List<Contract> contracts;

    ... getters and setters        
 }

这是合同实体

@Entity
@Table( name = "contract" )
@SequenceGenerator( name = "CONTRACT_SEQ_GEN", sequenceName = "CONTRACT_SEQUENCE" )
public class Contract
        implements DataObject<Long>
{

    /**
     * key for this instance. Should be managed by JPA provider.
     */
    @Id
    @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "CONTRACT_SEQ_GEN" )
    private Long key;

    /**
     * Organization that owns this contract, required.
     */
    @ManyToOne( optional=false )
    @JoinColumn( name="organization_key", referencedColumnName="key" )
    private Organization organization;

    /**
     * JPA version column
     */
    @Version
    protected int version;

    ... getters and setters
}

Using the EclipseLink JPA2 implementation (not sure if it's the same with the Hibernate implementation)

I have a simple structure where an Organization entity has contracts. Here's the sql I exported from postgres to create the Organization

CREATE TABLE organization (
    key bigint NOT NULL,
    version integer
);

If I specify the Contract side of the Organization like this:

@ManyToOne( optional=false )
@JoinColumn( name="organization_key", referencedColumnName="key" )
private Organization organization;

and then dump the schema I get this.

CREATE TABLE contract ( 
    key bigint NOT NULL, 
    version integer, 
    organization_key character varying(255), 
);

It doesn't make sense to me that it would use a character varying(255) field for the reference to the organization key. I know I can use the columnDefinition as follows:

@ManyToOne( optional=false )
@JoinColumn( name="organization_key", referencedColumnName="key", columnDefinition="bigint NOT NULL" )
private Organization organization;

to get the bigint type instead of the character type.

Is it unrealistic for me to expect it to get the correct column type? Am I using it wrong, or do I have the wrong expectations? Is it expected for me to have to use the columnDefinition each time?

Update:
Here's the relevant info from the Organization entity

@Entity
@Table( name = "organization" )
@SequenceGenerator( name = "ORGANIZATION_SEQ_GEN", sequenceName = "ORGANIZATION_SEQUENCE" )
public class Organization
        implements DataObject<Long>
{

    /**
     * key for this instance. Should be managed by JPA provider.
     */
    @Id
    @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "ORGANIZATION_SEQ_GEN" )
    private Long key;

    /**
     * JPA version column
     */
    @Version
    protected int version;

    /**
     * All contracts for this organization
     */
    @OneToMany(mappedBy="organization" )
    @OrderBy( "endDate DESC" )
    private List<Contract> contracts;

    ... getters and setters        
 }

And here's the Contract entity

@Entity
@Table( name = "contract" )
@SequenceGenerator( name = "CONTRACT_SEQ_GEN", sequenceName = "CONTRACT_SEQUENCE" )
public class Contract
        implements DataObject<Long>
{

    /**
     * key for this instance. Should be managed by JPA provider.
     */
    @Id
    @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "CONTRACT_SEQ_GEN" )
    private Long key;

    /**
     * Organization that owns this contract, required.
     */
    @ManyToOne( optional=false )
    @JoinColumn( name="organization_key", referencedColumnName="key" )
    private Organization organization;

    /**
     * JPA version column
     */
    @Version
    protected int version;

    ... getters and setters
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浊酒尽余欢 2024-10-06 03:17:09

我认为这个问题是区分大小写的。

您没有在 key id 属性上设置@Column,因此默认列名称为“KEY”。
在您的 @ManyToOne 中,您引用了“key”,它不是同一列,因此 EclipseLink(区分大小写并支持非 Id 外键引用)假设这是另一列,并且它不知道这一列,因此给出它是 VARCHAR 的默认类型。

将 referencedColumnName 更改为“KEY”或将其删除,因为引用单例 Id 时不需要它。

值得在 EclipseLink 上记录一个错误,即当未找到列引用或大小写错误(甚至可能自动切换大小写)时,应记录警告。实际上我们可能已经记录了警告,您可能希望检查您的日志。

I believe the issue is one of case sensitivity.

You did not set a @Column on the key id attribute, so the default column name is "KEY".
In your @ManyToOne you referenced "key", which is not the same column, so EclipseLink (which is case sensitive and supports non Id foreign key references) assumed this was a different column, and one that it did not know about, so gave it the default type of VARCHAR.

Either change the referencedColumnName to "KEY" or remove it as it is not required when referencing a singleton Id.

It would be worthwhile to log a bug on EclipseLink that a warning should be logged when a column reference is not found, or has the wrong case (maybe even switch the case automatically). Actually we might be logging a warning already, you may wish to check your log.

魂ガ小子 2024-10-06 03:17:08

我期望它获得正确的列类型是不现实的吗?

不,这并非不现实,目前的结果显然是出乎意料的。

是我用错了,还是我有错误的期望?

您的映射看起来没有错误。您能否尝试以下操作并确认您得到相同的结果(我只是省略了您不必定义的 referencedColumnName )?

@Entity
@Table( name = "contract" )
@SequenceGenerator( name = "CONTRACT_SEQ_GEN", sequenceName = "CONTRACT_SEQUENCE" )
public class Contract implements DataObject<Long> {
    @Id
    @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "CONTRACT_SEQ_GEN" )
    private Long key;
    ...
    @ManyToOne( optional=false )
    @JoinColumn( name="organization_key" )
    private Organization organization;
    ...
}

我没有安装 PostgreSQL,无法自行尝试。

我每次都必须使用columnDefinition吗?

不。

Is it unrealistic for me to expect it to get the correct column type?

No, it's not unrealistic and the current result is clearly unexpected.

Am I using it wrong, or do I have the wrong expectations?

Your mappings doesn't look wrong. Could you just try the following and confirm that you get the same result (I'm simply omitting the referencedColumnName that you should not have to define anyway)?

@Entity
@Table( name = "contract" )
@SequenceGenerator( name = "CONTRACT_SEQ_GEN", sequenceName = "CONTRACT_SEQUENCE" )
public class Contract implements DataObject<Long> {
    @Id
    @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "CONTRACT_SEQ_GEN" )
    private Long key;
    ...
    @ManyToOne( optional=false )
    @JoinColumn( name="organization_key" )
    private Organization organization;
    ...
}

I don't have PostgreSQL installed, can't try myself.

Is it expected for me to have to use the columnDefinition each time?

No.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文