Vikdor
Vikdor

Reputation: 24124

@OneToOne relationship between JPA entities that don't share any foreign key relationship

I have two entities as follows:

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

Answers (2)

Chris
Chris

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

Yogendra Singh
Yogendra Singh

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

Related Questions