22

Toplink can use read-only mappings when multiple attributes in an object map to the same fields in the database but only one of the mappings can write to the field.

Does JPA has such feature, how to write annotation? I have one @ManyToOne and one @Column annotation which need to map to same field in database.

@ManyToOne(optional=false, fetch=FetchType.LAZY)
@JoinColumn(name="USR_ID", referencedColumnName="USER_ID", nullable=false)
private User user;
    
/** @generated **/
@Column(name="USER_ID", nullable=false, length=30)
private String userId;
helvete
  • 2,455
  • 13
  • 33
  • 37
Jackie Dong
  • 813
  • 1
  • 5
  • 20

2 Answers2

50

From here

The Column annotation and XML element defines insertable and updatable options. These allow for this column, or foreign key field to be omitted from the SQL INSERT or UPDATE statement. These can be used if constraints on the table prevent insert or update operations. They can also be used if multiple attributes map to the same database column, such as with a foreign key field through a ManyToOne and Id or Basic mapping. Setting both insertable and updatable to false, effectively mark the attribute as read-only.

So

    @Column(name="USER_ID", nullable=false, length=30,
        updatable=false, insertable=false)
    private String userId;

should do it

Raniz
  • 10,882
  • 1
  • 32
  • 64
  • Even after using updatable and insertable, it still says "Unknown column 'xxx' in 'field list" – Anshul Gupta Dec 11 '18 at 05:29
  • @a-g: It sounds like you're having a different issue than the one solved here. Open a new question and provide some details and I'm sure someone will help you solve it! – Raniz Dec 11 '18 at 06:49
0

updatable=false, insertable=false might not be enough. Hibernate exposes additional requirement:

org.hibernate.DuplicateMappingException:
  Table [passenger] contains physical column name [parent_id]
  referred to by multiple logical column names: [parent_id], [parentId]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl$TableColumnNameBinding.bindPhysicalToLogical(InFlightMetadataCollectorImpl.java:1055)

The logical name parent_id comes from:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(insertable = false, updatable = false)
private Passenger parent;

while parentId comes from:

private Long parentId;

To harmonize logical names correct one (or set both) explicitly:

@Column(name = "parent_id")
private Long parentId;

Requirements for updatable=false, insertable=false comes from:

for ( Selectable columnOrFormula : value.getSelectables() ) {
  if ( !columnOrFormula.isFormula() ) {
    Column col = (Column) columnOrFormula;
    if ( !distinctColumns.add( col.getName() ) ) {
      throw new MappingException(
        "Column '" + col.getName()
           + "' is duplicated in mapping for entity '" + getEntityName()
           + "' (use '@Column(insertable=false, updatable=false)' when mapping multiple properties to the same column)"

located:

at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:1009)
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:1027)
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:1055)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:720)
at org.hibernate.mapping.RootClass.validate(RootClass.java:283)
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:376)
gavenkoa
  • 45,285
  • 19
  • 251
  • 303