Reputation: 7731
I have a case where I'm persisting a large jsonb
field into a PostGres table, but do not want to read it when I fetch the entity; if I do fetch it, my service goes OOM. A better design might be to separate this into a 1 to 1 table, but I can't do that at this time.
To plead that this is not a duplicate question, here's some of my research:
LAZY
since I have a simple column not a join`
JPA/Hibernate write only field with no read@Data
class: Omitting one Setter/Getter in LombokSo, I can not see the field, but I can't seem to keep it from being read into memory in the background. It seems like there must be some simple setting in JPA or Hibernate to exclude a column from read. Before I go try to make a complex repository hierarchy just to see if it works, I thought I would ask here in case I get lucky.
Thanks in advance!
Upvotes: 0
Views: 1361
Reputation: 8216
Hibernate can load attribute lazily, but you need to enable byte code enhancements:
First you need to set the property hibernate.enhancer.enableLazyInitialization
to true
Then you can annotate the field with @Basic( fetch = FetchType.LAZY )
.
Here's the example from the documentation:
@Entity
public class Customer {
@Id
private Integer id;
private String name;
@Basic( fetch = FetchType.LAZY )
private UUID accountsPayableXrefId;
@Lob
@Basic( fetch = FetchType.LAZY )
@LazyGroup( "lobs" )
private Blob image;
//Getters and setters are omitted for brevity
}
You can also enable this feature via the Hibernate ORM gradle plugin
You could also decide to not map it and save/read it with a named native query. It seems a good trade off for a single attribute - it will just require an additional query to save the json.
Example:
@Entity
@Table(name = "MyEntity_table")
@NamedNativeQuery(
name = "write_json",
query = "update MyEntity_table set json_column = :json where id = :id")
@NamedNativeQuery(
name = "read_json",
query = "select json_column from MyEntity_table where id = :id")
class MyEntity {
....
}
Long id = ...
String jsonString = ...
session.createNamedQuery( "write_json" )
.setParameter( "id", id )
.setParameter( "json", jsonString )
.executeUpdate();
jsonString = (String)session.createNamedQuery( "read_json" )
.setParameter( "id", id )
.getSingleResult();
In this case, schema generation is not going to create the column, so you will need to add it manually (not a big deal, considering that there are better tools to update the schema in production).
You can also have two entities extending the same superclass (this way you don't have to copy the attributes). They have to update the same table:
@MappedSuperclass
class MyEntity {
@Id
Long id;
String name
...
}
@Entity
@Table(name = "MyEntity_table")
class MyEntityWriter extends MyEntity {
String json
}
@Entity
@Table(name = "MyEntity_table")
class MyEntityReader extends MyEntity {
// No field is necessary here
}
Now you can use MyEntityWriter
for saving all the values and MyEntityReader
for loading only the values you need.
I think you will have some problems with schema generation if you try to create the tables because only one of the two will be created:
MyEntityWriter
is the first table created, then no problemMyEntityWriter
is the second table created, the query will fail because the table already exist and the additional column won't be created.I haven't tested this solution though, there might be something I haven't thought about.
Upvotes: 2