Home > Blockchain >  Is there a way to retrieve an entity with list property but load the list with the last few entities
Is there a way to retrieve an entity with list property but load the list with the last few entities

Time:10-25

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).

  • Related