4

I don't know how to force read-only columns in Hibernate.

I would like to set idgroup as read only column. Even if I set insertable=false and updatable=false, in the hibernate SQL I can read:

Hibernate: insert into groups (description, name, account_idaccount, idgroup) values (?, ?, ?, ?) 

but I would like to obtain:

insert into groups (description, name, account_idaccount) values (?, ?, ?) 

Here are my classes:

@Entity
@Table(name = "groups")
public class Group implements java.io.Serializable {

private static final long serialVersionUID = -2948610975819234753L;
private GroupId id;
private Account account;
private String name;
private String description;

@EmbeddedId
@AttributeOverrides({@AttributeOverride(name = "idgroup", column = @Column(name = "idgroup", insertable = false)),
        @AttributeOverride(name = "accountIdaccount", column = @Column(name = "account_idaccount", nullable = false))})
public GroupId getId() {
    return id;
}

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "account_idaccount", nullable = false, insertable = false, updatable = false)
public Account getAccount() {
    return account;
}

@Column(name = "description", length = 512)
public String getDescription() {
    return description;
}


@Column(name = "name", nullable = false, length = 128)
public String getName() {
    return name;
}
..
}
@Embeddable
public class GroupId implements java.io.Serializable {

private int idgroup;
private int accountIdaccount;

@Column(name = "idgroup", insertable= false, updatable= false)
public int getIdgroup() {
    return this.idgroup;
}


@Column(name = "account_idaccount", nullable = false)
public int getAccountIdaccount() {
    return this.accountIdaccount;
}
..
}

I would like to have a read only column for idgroup because I can exploit the id auto-generation of the DBMS, I do not want to use the key auto-generation in Hibernate because it is not cluster-safe.

approxiblue
  • 6,982
  • 16
  • 51
  • 59
cloudy_weather
  • 2,837
  • 12
  • 38
  • 63
  • have a look at http://docs.jboss.org/hibernate/orm/3.5/reference/en-US/html/readonly.html and http://ndpsoftware.com/HibernateMappingCheatSheet.html - they may give you hints – Rachel Gallen Jan 31 '13 at 13:07
  • thanks Rachel, but the first link refers to read only entities, and I don't see the second useful to my case – cloudy_weather Jan 31 '13 at 13:19
  • ah well. thought you could set the optimistic lock to true – Rachel Gallen Jan 31 '13 at 13:25
  • Is it good for you if hibernate instead of not trying to persist your readonly value just persist always the same what he collected when getting entity from dbms? – Michał Kupisiński Jan 31 '13 at 14:02
  • the problem is when I create an instance from Java and I want to save it in the database, even if I don't initialize the idgroup, hibernate writes 0 because it is the default value for int. – cloudy_weather Jan 31 '13 at 15:04
  • This wasn't tagged with JPA, but my guess is you will need to specify a SequenceGenerator to get it to use your database's sequencing, otherwise it will not be usable in relationships etc. You are also overriding your column to only be insertable=false - someone else suggested it be marked both insertable+updatable=false – Chris Feb 01 '13 at 19:16

5 Answers5

15

I think you can mark an @Column annotation as updatable=false

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
Bob Flannigon
  • 1,204
  • 9
  • 8
6

Easy:

@Column(insertable = false, updatable = false)
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
J. Jerez
  • 704
  • 8
  • 6
0

I was able to achieve this by using 2 DAO objects. I know it may not be preferred, but I didn't see another way around it. Setting the field to insertable=false and updatable=false do not remove the columns from the insert SQL so Postgres will not invoke the default action to populate those column values.

   // GroupWrite

   @Entity
   @Table(name = "group")
   public class GroupWrite {

      @Id
      @Column(name = "account")
      private Account account;

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

      @Column(name = "description")
      private String description;


      /* Getters and Setters */
  }

--

   // GroupRead

   @Entity
   @Table(name = "group")
   public class GroupRead {

      @EmbeddedId
      @Column(name = "id")
      private GroupId id;

      @Column(name = "account")
      private Account account;

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

      @Column(name = "description")
      private String description;


      /* Getters and Setters */
  }

Then you need to use the GroupRead when using select queries and GroupWrite when doing insert or update queries.

If you want to use attributes from both in a common way you can implement an interface that describes the overlapping fields.

   public interface Group {

        Account getAccount();

        void setAccount(Account account);
   }

   public class GroupWrite implements Group {...}

   public class GroupRead implements Group {...}

Hope this helps.

wheeleruniverse
  • 1,511
  • 2
  • 20
  • 37
-2

The solution is using wrapper classes, such as Integer, not primitive types like int. When Hibernate will get a null pointer it will delegate the generation of the id to the DBMS.

try-catch-finally
  • 7,436
  • 6
  • 46
  • 67
cloudy_weather
  • 2,837
  • 12
  • 38
  • 63
-3

@ReadOnlyProperty annotation will help you in this case.

Rakesh
  • 1
  • It's always useful to add an explanation on *how* would things help. – Tavo Aug 18 '15 at 09:41
  • 1
    It didn't help me. At least the one I found, which was org.springframework.data.annotation.ReadOnlyProperty. I didn't find a Hibernate property by that name. – MiguelMunoz Feb 13 '18 at 20:35