Jackie Dong
Jackie Dong

Reputation: 813

JPA readonly mapping

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;

Upvotes: 21

Views: 31114

Answers (2)

gavenkoa
gavenkoa

Reputation: 48853

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)

Upvotes: 0

Raniz
Raniz

Reputation: 11113

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

Upvotes: 51

Related Questions