JPA OneToOne 关联,其中 2 个实体使用复合主键但使用不同的列名称?

发布于 2024-10-11 03:31:05 字数 4105 浏览 5 评论 0原文

我们正在尝试将 Hibernate 与使用大量复合键的数据库一起使用,这给我们带来了很多麻烦。 不幸的是,我们无法更改架构,因此我们必须在字段之间进行大量额外的映射。我们仅限于使用 JPA 1.0 和 Hibernate 3.3。

最大的问题 到目前为止,我们使用 2 个值的组合键来处理两个实体之间的一对一关联,其中表具有不同的名称 对于这些列(数据库的命名约定是在每列上都有特定于表的前缀。)

每当我们执行查询时,都会遇到此异常:

Caused by: org.hibernate.TypeMismatchException Provided id of the wrong type for class com.business.entity.InvestorIssuerEmailEntity.  
Expected: class com.business.entity.InvestorIssuerEmailEntityPK, got class com.business.entity.InvestorIssuerEntityPK; 

这些表的两个类 InvestorIssuerEntity 和 InvestorIssuerEmailEntity 有一个可选的 @OneToOne 关联 (在某些情况下,InvestorIssuer 在 InvestorIssuerEmail 中没有匹配记录):

@IdClass(InvestorIssuerEntityPK.class)
@Table(name = "T090_INVESTOR_ISSUER")
@Entity
InvestorIssuerEntity
    @Column(name = "T090_091_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long investorId;

    @Column(name = "T090_102_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long issuerId;

(other fields omitted)

    @OneToOne(optional = true)
    @JoinColumns(value = {
            @JoinColumn(name="T090_091_INVESTOR_ID", referencedColumnName = "T284_INVESTOR_ID", nullable = false, insertable = false, updatable = false),
            @JoinColumn(name = "T090_102_ISSUER_ID", referencedColumnName = "T284_ISSUER_ID", nullable = false, insertable = false, updatable = false)
    })
    @NotFound(action = NotFoundAction.IGNORE)
    private InvestorIssuerEmailEntity investorIssuerEmail;

... 

InvestorIssuerEntityPK 
    @Id
    @Column(name = "T090_091_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    private Long investorId;

    @Id
    @Column(name = "T090_102_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    private Long issuerId;

...

@IdClass(InvestorIssuerEmailEntityPK.class)
@Table(name = "T284_INVESTOR_ISSUER_EMAIL")
@Entity
InvestorIssuerEmailEntity
    @Column(name = "T284_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long investorId;

    @Column(name = "T284_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long issuerId;

...

InvestorIssuerEmailEntityPK 

    @Column(name = "T284_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long investorId;

    @Column(name = "T284_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long issuerId;  

我尝试通过使用与两个实体的 @EmbeddableId 相同的类,然后使用 @AttributeOverrides 来解决类型不匹配问题,如下所示:

@Id
@EmbeddedId
@AttributeOverrides({
        @AttributeOverride(name = "investorId",
                column = @Column(name = "T284_INVESTOR_ID", nullable = false, insertable = true, updatable = true, length = 18, precision = 0)),
        @AttributeOverride(name = "issuerId",
                column = @Column(name = "T284_ISSUER_ID", nullable = false, insertable = true, updatable = true, length = 18, precision = 0))
})
private InvestorIssuerId investorIssuerId;

我只做了尽管对这两个实体进行了更改,但仍然对其他实体使用 @IdClass 方法(是否仅对您的实体使用 @IdClass 或 @EmbeddableId,而不是两者都使用?)

我们最终遇到了其他问题,例如“重复列实体的映射”,因此我们恢复了这种方法,看看是否有其他解决方法。

有没有人有任何解决方案来解决这个问题?我查看了 StackOverflow,但没有遇到关联中使用的组合键具有不同名称的任何情况。

注意: 即使尝试下面的建议后,我们仍然收到此错误:org.hibernate.MappingException:实体映射中的重复列:com.business.entity.InvestorIssuerEntity列:T090_091_INVESTOR_ID(应使用 insert="false" update="false 进行映射")

我什至从 InvestorIssuerEntity 中删除了所有关联,仍然遇到同样的问题。当我删除复合键类中的 @Column 注释时,该错误才消失。当然,查询不起作用,因为投资者 ID 没有映射!我不明白 Hibernate 在哪里找到“映射中的重复列”,因为除了复合键之外,我已经删除了所有提到的 T090_091_INVESTOR_ID 。

我们在 InvestorIssuerEntity 中还有其他关联,它们对相同的主键进行联接,但关联实体的组合键中也有附加列。一旦使用@EmbeddedId,您是否应该将它们用于所有实体?我们仍然对其他类使用@IdClass。但这是如何导致任何地方出现“重复列”的呢?

We are trying to use Hibernate with a database that uses a lot of composite keys and it's been causing us a lot of headaches.
Unfortunately, we can't change the schema so we have to do a lot of additional mapping betwen our fields. We are restricted to using JPA 1.0 and Hibernate 3.3.

The biggest problem
we've had so far is to do with a one-to-one association between two entities using a composite key of 2 values, where the tables have different names
for these columns (the DB has a naming convention of having a table-specific prefix on each column.)

Whenever we perform our query, we get this exception:

Caused by: org.hibernate.TypeMismatchException Provided id of the wrong type for class com.business.entity.InvestorIssuerEmailEntity.  
Expected: class com.business.entity.InvestorIssuerEmailEntityPK, got class com.business.entity.InvestorIssuerEntityPK; 

The two classes for these tables, InvestorIssuerEntity and InvestorIssuerEmailEntity, have an optional @OneToOne assocation
(in some cases InvestorIssuer has no matching record in InvestorIssuerEmail):

@IdClass(InvestorIssuerEntityPK.class)
@Table(name = "T090_INVESTOR_ISSUER")
@Entity
InvestorIssuerEntity
    @Column(name = "T090_091_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long investorId;

    @Column(name = "T090_102_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long issuerId;

(other fields omitted)

    @OneToOne(optional = true)
    @JoinColumns(value = {
            @JoinColumn(name="T090_091_INVESTOR_ID", referencedColumnName = "T284_INVESTOR_ID", nullable = false, insertable = false, updatable = false),
            @JoinColumn(name = "T090_102_ISSUER_ID", referencedColumnName = "T284_ISSUER_ID", nullable = false, insertable = false, updatable = false)
    })
    @NotFound(action = NotFoundAction.IGNORE)
    private InvestorIssuerEmailEntity investorIssuerEmail;

... 

InvestorIssuerEntityPK 
    @Id
    @Column(name = "T090_091_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    private Long investorId;

    @Id
    @Column(name = "T090_102_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    private Long issuerId;

...

@IdClass(InvestorIssuerEmailEntityPK.class)
@Table(name = "T284_INVESTOR_ISSUER_EMAIL")
@Entity
InvestorIssuerEmailEntity
    @Column(name = "T284_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long investorId;

    @Column(name = "T284_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long issuerId;

...

InvestorIssuerEmailEntityPK 

    @Column(name = "T284_INVESTOR_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long investorId;

    @Column(name = "T284_ISSUER_ID", nullable = false, insertable = true, 
updatable = true, length = 18, precision = 0)
    @Id
    private Long issuerId;  

I've tried to get around the Type Mismatch problem by using the same class as the @EmbeddableId for the two entities, and then using @AttributeOverrides, like this:

@Id
@EmbeddedId
@AttributeOverrides({
        @AttributeOverride(name = "investorId",
                column = @Column(name = "T284_INVESTOR_ID", nullable = false, insertable = true, updatable = true, length = 18, precision = 0)),
        @AttributeOverride(name = "issuerId",
                column = @Column(name = "T284_ISSUER_ID", nullable = false, insertable = true, updatable = true, length = 18, precision = 0))
})
private InvestorIssuerId investorIssuerId;

I only did the change for these two entities though, still using the @IdClass approach for the other entities (Is it a case of only using @IdClass OR @EmbeddableId for your entities, not both?)

We ended up getting other issues like "Repeated column in mapping for entity", so we've reverted to this approach to see if there's other workarounds to this.

Does anyone have any solutions to get around this problem? I've looked around StackOverflow but haven't come across any cases where the composite keys used in the association have different names.

Note:
Even after trying the suggestion below, we still get this error: org.hibernate.MappingException: Repeated column in mapping for entity: com.business.entity.InvestorIssuerEntity column: T090_091_INVESTOR_ID (should be mapped with insert="false" update="false")

I even removed ALL associations from InvestorIssuerEntity and still got the same problem. The error only went away when I removed the @Column annotation in the composite key class. Of course, the queries didn't work because the investorId wasn't mapped! I don't understand where Hibernate was finding the "Repeated column in mapping", since I'd already removed every mention of T090_091_INVESTOR_ID else except for the composite key.

We have other associations in InvestorIssuerEntity that do a join on the same primary keys, but the associated entities also have additional columns in their composite keys. Once you use @EmbeddedId, are you supposed to use them for all entities? We still use @IdClass for the others classes. But then how does that cause a "repeated column" anywhere?

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

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

发布评论

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

评论(2

新人笑 2024-10-18 03:31:05

看来我为您的情况找到了一个有效的解决方案:

@Entity
public class InvestorIssuerEntity {
    @EmbeddedId 
    private InvestorIssuerEntityPK investorIssuerEntityPK;

    @OneToOne(optional=true, mappedBy="investorIssuerEntity")
    private InvestorIssuerEmailEntity investorIssuerEmailEntity;
}

@Entity
public class InvestorIssuerEmailEntity {
    @EmbeddedId @AttributeOverrides({
        @AttributeOverride(name="investorId", column=@Column(name="T02_INV_ID")),
        @AttributeOverride(name="issuerId", column=@Column(name="T02_ISS_ID"))
    })
    private InvestorIssuerEntityPK investorIssuerEntityPK;

    @OneToOne(optional=true) @PrimaryKeyJoinColumns({
        @PrimaryKeyJoinColumn(name="T02_ISS_ID", referencedColumnName="T01_ISS_ID"), 
        @PrimaryKeyJoinColumn(name="T02_INV_ID", referencedColumnName="T01_INV_ID")
    })
    private InvestorIssuerEntity investorIssuerEntity;
}

@Embeddable
public class InvestorIssuerEntityPK implements Serializable {
    private static final long serialVersionUID = -1176248537673293674L;

    @Column(name="T01_INV_ID")
    private Long investorId;

    @Column(name="T01_ISS_ID")
    private Long issuerId;
}

它生成以下 DDL,这似乎正是您正在寻找的:

create table InvestorIssuerEmailEntity (
    T02_INV_ID bigint not null,
    T02_ISS_ID bigint not null,
    primary key (T02_INV_ID, T02_ISS_ID)
)

create table InvestorIssuerEntity (
    T01_INV_ID bigint not null,
    T01_ISS_ID bigint not null,
    primary key (T01_INV_ID, T01_ISS_ID)
)

alter table InvestorIssuerEmailEntity 
    add constraint FKC2FBCC4E1E26612E 
    foreign key (T02_INV_ID, T02_ISS_ID) 
    references InvestorIssuerEntity

It seems I got a working solution for your case:

@Entity
public class InvestorIssuerEntity {
    @EmbeddedId 
    private InvestorIssuerEntityPK investorIssuerEntityPK;

    @OneToOne(optional=true, mappedBy="investorIssuerEntity")
    private InvestorIssuerEmailEntity investorIssuerEmailEntity;
}

@Entity
public class InvestorIssuerEmailEntity {
    @EmbeddedId @AttributeOverrides({
        @AttributeOverride(name="investorId", column=@Column(name="T02_INV_ID")),
        @AttributeOverride(name="issuerId", column=@Column(name="T02_ISS_ID"))
    })
    private InvestorIssuerEntityPK investorIssuerEntityPK;

    @OneToOne(optional=true) @PrimaryKeyJoinColumns({
        @PrimaryKeyJoinColumn(name="T02_ISS_ID", referencedColumnName="T01_ISS_ID"), 
        @PrimaryKeyJoinColumn(name="T02_INV_ID", referencedColumnName="T01_INV_ID")
    })
    private InvestorIssuerEntity investorIssuerEntity;
}

@Embeddable
public class InvestorIssuerEntityPK implements Serializable {
    private static final long serialVersionUID = -1176248537673293674L;

    @Column(name="T01_INV_ID")
    private Long investorId;

    @Column(name="T01_ISS_ID")
    private Long issuerId;
}

It generates the following DDL, which seems to be what you are looking for:

create table InvestorIssuerEmailEntity (
    T02_INV_ID bigint not null,
    T02_ISS_ID bigint not null,
    primary key (T02_INV_ID, T02_ISS_ID)
)

create table InvestorIssuerEntity (
    T01_INV_ID bigint not null,
    T01_ISS_ID bigint not null,
    primary key (T01_INV_ID, T01_ISS_ID)
)

alter table InvestorIssuerEmailEntity 
    add constraint FKC2FBCC4E1E26612E 
    foreign key (T02_INV_ID, T02_ISS_ID) 
    references InvestorIssuerEntity
找个人就嫁了吧 2024-10-18 03:31:05

我想提一下另一种方法:

  • 优点:两个实体都可以使用自己的 PK 类
  • 缺点:1:1 关系体现在具有 1 个条目的 Set 中

您可以切换到 @OneToMany 关系并将相关实体存储在 Set 中。该集合将有 1 个条目,可以在后处理步骤中将其解包。

@OneToMany
@JoinColumns(value = {
        @JoinColumn(name="T090_091_INVESTOR_ID", referencedColumnName = "T284_INVESTOR_ID", nullable = false, insertable = false, updatable = false),
        @JoinColumn(name = "T090_102_ISSUER_ID", referencedColumnName = "T284_ISSUER_ID", nullable = false, insertable = false, updatable = false)
})
@NotFound(action = NotFoundAction.IGNORE)
private Set<InvestorIssuerEmailEntity> investorIssuerEmails;

I want to mention an alternative approach:

  • pro: Both entities can use their own PK class
  • con: The 1:1 relation manifests in a Set with 1 entry

You can switch to a @OneToMany Relation and store the related entity in a Set. The Set will have 1 entry, which can be unpacked in a post-processing step.

@OneToMany
@JoinColumns(value = {
        @JoinColumn(name="T090_091_INVESTOR_ID", referencedColumnName = "T284_INVESTOR_ID", nullable = false, insertable = false, updatable = false),
        @JoinColumn(name = "T090_102_ISSUER_ID", referencedColumnName = "T284_ISSUER_ID", nullable = false, insertable = false, updatable = false)
})
@NotFound(action = NotFoundAction.IGNORE)
private Set<InvestorIssuerEmailEntity> investorIssuerEmails;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文