Let's say I have the following entities in my application:
@Data
@Entity
public class SomeEntity {
@Id
private Long id;
@OneToMany
private List<AnotherEntity> anotherEntities = new ArrayList<>();
@Version
private Long version;
}
@Data
@Entity
public class AnotherEntity {
@Id
private Long id;
@Column
private String someField;
@Column
private Long version;
}
Question 1:
I want to load a SomeEntity with id = 1 for example, but I only want to load the anotherEntities partially, for example I only want the last 10 versions of it, what is the easiest and most straight forward way of doing it (with Hibernate/Spring Data JPA) with one request?
Question 2:
I want to update the previously mentioned object and add a new AnotherEntity to the list, but the save(T t) method of JpaRepository saves the whole object and I lose the ones that weren't loaded. How can I save the object so that the version will be updated by Spring Data (Optimistic Locking) and the SomeEntity won't lose previous data?
Update 1:
I am using Postgresql for database.
CodePudding user response:
You have different options depending on your exact constraints.
You can use the @Where
annotation:
@Data
@Entity
public class SomeEntity {
@Id
private Long id;
@OneToMany
@Where(clause = "version < 10")
private List<AnotherEntity> anotherEntities = new ArrayList<>();
@Version
private Long version;
}
You can use a filter:
@Data
@Entity
public class SomeEntity {
@Id
private Long id;
@OneToMany
@Filter(
name="latestVersions",
condition="version < :version"
)
private List<AnotherEntity> anotherEntities = new ArrayList<>();
}
You can enable filters before running a query with the session:
entityManager
.unwrap(Session.class)
.enableFilter("latestVersions")
.setParameter("version", 10);
List<Account> accounts = entityManager.createQuery(
"from SomeEntity se where se.id = 1", SomeEntity.class)
.getResultList();
You can map the association as bidirectional (or as a many-to-one)
@Data
@Entity
public class SomeEntity {
@Id
private Long id;
@OneToMany(mappedBy = "someEntity")
private List<AnotherEntity> anotherEntities = new ArrayList<>();
@Version
private Long version;
}
@Data
@Entity
public class AnotherEntity {
@Id
private Long id;
@Column
private String someField;
@Column
private Long version;
@ManyToOne
private SomeEntity someEntity;
}
Now you can get the list of entities using an HQL query:
from AnotherEntity ae where ae.someEntity.id = 1 and ae.version < 10
When you want to create a new AnotherEntity
, you can get SomeEntity
from any element in the result list, or you can use EntityManager#getReference
(and avoid running the query):
AnotherEntity ae = new AnotherEntity(...);
ae.setSomeEntity(em.getReference(SomeEntity.class, 1));
em.persist(ae);
The association is lazy, so Hibernate is not going to load the whole collection (unless you need to access it).