Reputation: 24124
I have two entities as follows:
Invoice
InvoiceId
[OrgId, VendorId, VendorInvoiceId]
InvoiceState
InvoiceStateId
[OrgId, VendorId, VendorInvoiceId]
The "other columns of interest" form a unique key in both the tables, except that the second table, InvoiceState
, can contain records that doesn't have a corresponding record in the first table, Invoice
.
At the entity layer, I would like define Invoice
entity to contain a reference to InvoiceState
entity with a @OneToOne
relationship defined, with @JoinColumns
as follows:
@OneToOne
@JoinColumns
({
@JoinColumn(name="OrgId", referencedColumnName="OrgId"),
@JoinColumn(name="VendorId", referencedColumnName="VendorId"),
@JoinColumn(name="VendorInvoiceId", referencedColumnName="VendorInvoiceId")
})
But this throws an exception that the foreign key count is not the same in both entities. I don't even have a foreign key defined between these two tables.
Is there a way to define a @OneToOne
relationship between two entities that don't share Foreign Keys, but have a set of column that can be used during JOIN
?
Upvotes: 1
Views: 1183
Reputation: 21145
If the three fields are unique, you can mark them as the PK for the InvoicesState entity, which then allows state to reference them in a oneToOne. The PK used for JPA doesnt need to match the table id, it just needs to be unique.
Some providers do allow referencing non-PK fields in mappings. This isn't always suggested though because the entities are usually cached on PKs, so you may get extra database hits to resolve the reference. In Eclipselink, you could fake the mapping out by using only one of the fields, and correct the mapping in a descriptor customizer to add the remaining fields in the relationship.
Upvotes: 1
Reputation: 34367
I would advice to map the above 3 columns as a component
using @Embeddable
and use the component in for mapping using @Embedded
and defining the joining condition.
e.g. below:
@Embeddable
public class ReferenceInfo {
private Long orgId = null;
private Long vendorId= null;
private Long vendorInvoiceId= null;
.........
.........
}
@Entity
public class Invoces{
private Long invoiceId = null;
private ReferenceInfo refInfo = null;
private InvoiceStates invoiceStates = null;
@Id
public Long getInvoiceId(){
return invoiceId;
}
......
@Embedded
public ReferenceInfo getRefInfo(){
....
}
@OneToOne(mappedBy="refInfo"))
public InvoiceStates getInvoiceStates(){
return invoiceStates;
}
}
@Entity
public class InvoiceStates {
private Long invoiceStateId = null;
private ReferenceInfo refInfo = null;
@Id
public Long getInvoiceStateId(){
return invoiceStateId;
}
......
@Embedded
public ReferenceInfo getRefInfo(){
....
}
}
Upvotes: 1