2

Hi I've the following code (using eclipselink 2.6):

Transmission:

@Entity    
public class Transmission {     

    @Column(name="TRANSMISSION_ID")
    @Id private Long id;

    @Column(name="TRANSMISSION_CONTENT")
    private String content;
....
}

HeaderPk:

@Embeddable
public class HeaderPk {

    // this is a foreign key to "TRANSMISSION_ID" in Transmission
    @Column(name="FK_TRANSMISSION_ID")
    private Long transmissionId;

    @Column(name="MAILBOX_ID")
    private String mailboxId;

    @Column(name="TRANSMISSION_TIME")
    private Time transmissionTime;
    ...
}

Header:

@MappedSuperclass
public abstract class Header {

    @EmbeddedId
    private HeaderPk id = new HeaderPk();

    @MapsId("transmissionId")
    @ManyToOne(fetch=FetchType.EAGER) 
    @JoinColumn(name="FK_TRANSMISSION_ID", referencedColumnName="TRANSMISSION_ID")
    private Transmission transmission;        
    ....
}

VoucherHeader:

@Entity
public class VoucherHeader extends Header {
    // a bunch of additional fields
    ....
    ....    
}

RecordPk:

@Embeddable
public class RecordPk {

    @Column(name="RECORD_NUMBER")
    private Integer recordNumber;

    @Embedded   
    private HeaderPk headerPk;
    ...
    ...
}

Record:

@MappedSuperclass
public abstract class Record<T> {

    @EmbeddedId
    private RecordPk id;

    @MapsId("headerPk")
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="FK_TRANSMISSION_ID", referencedColumnName="FK_TRANSMISSION_ID"),
        @JoinColumn(name="FK_MAILBOX_ID", referencedColumnName="MAILBOX_ID"),
        @JoinColumn(name="FK_TRANSMISSION_TIME", referencedColumnName="TRANSMISSION_TIME")
    })
    private T header;
    ....
    ....
}

VoucherRecordTypeA:

@Entity
public class VoucherRecordTypeA extends Record<VoucherHeader> {
    // a bunch of additional column-mapped fields
    ...
}

When attempting to run the program I get the following error: There should be one non-read-only mapping defined for the primary key field [VoucherRecordTypeA.MAILBOX_ID]...I know it's complaining about having more than writable mapping field but I'm unable to figure out how to fix this.

The error disappears if I modify VoucherRecordTypeA to this...

@Entity
public class VoucherRecordTypeA  {
    @EmbeddedId
    private RecordPk id;

    @MapsId("headerPk")
    @ManyToOne
        @JoinColumns({
            @JoinColumn(name="FK_TRANSMISSION_ID", referencedColumnName="FK_TRANSMISSION_ID"),
            @JoinColumn(name="FK_MAILBOX_ID", referencedColumnName="MAILBOX_ID"),
            @JoinColumn(name="FK_TRANSMISSION_TIME", referencedColumnName="TRANSMISSION_TIME")
    })
    private VoucherHeader header;

    // a bunch of additional column-mapped fields
    ...
}

But the desired solution is to have VoucherRecordTypeA extends Record<...> since there are several other classes similar to VoucherRecordTypeA. Any assistance will be appreciated.

Edit Tried the following

@MappedSuperclass
public abstract class Record {              
    @EmbeddedId
    private RecordPk id;

    @MapsId("headerPk")
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="FK_TRANSMISSION_ID", referencedColumnName="FK_TRANSMISSION_ID"),
        @JoinColumn(name="FK_MAILBOX_ID", referencedColumnName="MAILBOX_ID"),
        @JoinColumn(name="FK_TRANSMISSION_TIME", referencedColumnName="TRANSMISSION_TIME")
    })
    private VoucherHeader header;
    ....
    ....
}

Same error. I noticed that it's complaining that non-read-only mapping should be defined for [VoucherRecordTypeA.MAILBOX_ID]...the table VoucherRecordTypeA has the column FK_MAILBOX_ID not MAILBOX_ID...MAILBOX_ID is the referenced column in the VoucherHeader table.

theprogrammer
  • 57
  • 2
  • 7

1 Answers1

1

It seems that EclipseLink will not complain if the name of the column and the referenced column in @JoinColumn are same. So this gives no errors:

@MappedSuperclass
public abstract class Record {              
@EmbeddedId
private RecordPk id;

@MapsId("headerPk")
@ManyToOne
@JoinColumns({
    @JoinColumn(name="FK_TRANSMISSION_ID", referencedColumnName="FK_TRANSMISSION_ID"),
    @JoinColumn(name="MAILBOX_ID", referencedColumnName="MAILBOX_ID"),
    @JoinColumn(name="TRANSMISSION_TIME", referencedColumnName="TRANSMISSION_TIME")
})
private VoucherHeader header;
....
....
}

However this is not acceptable since the actual column names are different from the referenced column names. And like I stated in my original post this is not a problem if I move RecordPk and the relationship mapping into VoucherRecordTypeA with the correct column name in the @JoinColumn annotation. I went ahead and tried this solution and it gives me no errors.

@Embeddable
public class RecordPk {

@Column(name="RECORD_NUMBER")
private Integer recordNumber;

@Column(name="FK_TRANSMISSION_ID", insertable=false, updatable=false)
private Long transmissionId;

@Column(name="FK_MAILBOX_ID", insertable=false, updatable=false)
private String mailboxId;

@Column(name="FK_TRANSMISSION_TIME", insertable=false, updatable=false)
private Time transmissionTime;
...
...
}

So basically I removed the embedded HeaderPk from RecordPk and added the individual fields. The rest of the code is the same as in the original post. And EclipseLink is not complaining anymore.

This is my analysis: This problem happens only on a class annotated with @MappedSuperclass. Using a derived EmbeddedId with a nested id in a @MappedSuperclass along with @JoinColumn on a relationship will work as long as the column name and referenced column name are the same. It breaks if they're not the same. However this doesn't happen when you've the same setup on a class annotated with @Entity. Following the code in the post might give a better understanding.

Is my analysis correct? Is this a bug?

EDIT: I forgot to mention...in Record you need to remove the @MapsId("headerPk") since headerPk is no longer embedded into RecordPk.

theprogrammer
  • 57
  • 2
  • 7