应该为主键字段定义一个 non-read-only 映射

There should be one non-read-only mapping defined for the primary key field

您好,我有以下代码(使用 eclipselink 2.6):

传输:

@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;        
    ....
}

代金券Header:

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

记录Pk:

@Embeddable
public class RecordPk {

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

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

记录:

@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
    ...
}

尝试 运行 程序时出现以下错误: 应该为主键字段 [VoucherRecordTypeA.MAILBOX_ID] 定义一个 non-read-only 映射...我知道它抱怨有超过 writable 映射字段但我无法弄清楚如何解决这个问题。

如果我将 VoucherRecordTypeA 修改为这个,错误就会消失...

@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
    ...
}

但理想的解决方案是让 VoucherRecordTypeA 扩展 Record<...>,因为还有其他几个 类 类似于 VoucherRecordTypeA。如有任何帮助,我们将不胜感激。

编辑 尝试了以下

@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;
    ....
    ....
}

同样的错误。我注意到它在抱怨应该为 [VoucherRecordTypeA.MAILBOX_ID] 定义 non-read-only 映射...table VoucherRecordTypeA 具有列 FK_MAILBOX_ID 不是 MAILBOX_ID...MAILBOX_ID 是凭证中引用的列Header table.

如果列名和@JoinColumn 中引用的列相同,EclipseLink 似乎不会报错。所以这没有错误:

@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;
....
....
}

但是这是不可接受的,因为实际的列名与引用的列名不同。就像我在原来的 post 中所说的那样,如果我将 RecordPk 和关系映射移动到 VoucherRecordTypeA 中并在 @JoinColumn 注释中使用正确的列名,这不是问题。我继续尝试这个解决方案,它没有给我任何错误。

@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;
...
...
}

所以基本上我从 RecordPk 中删除了嵌入的 HeaderPk 并添加了各个字段。其余代码与原始代码相同 post。 EclipseLink 不再抱怨了。

这是我的分析:这个问题只发生在用 @MappedSuperclass 注释的 class 上。只要列名和引用的列名相同,在 @MappedSuperclass 中使用带有嵌套 ID 的派生 EmbeddedId 以及关系上的 @JoinColumn 将起作用。如果它们不相同,它就会中断。但是,当您在使用 @Entity 注释的 class 上进行相同设置时,不会发生这种情况。遵循 post 中的代码可能会更好地理解。

我的分析正确吗?这是一个错误吗?

编辑: 我忘了提...在记录中你需要删除 @MapsId("headerPk")因为 headerPk 不再嵌入到 RecordPk 中。