0

I experienced poor performance when using em.find(entity, primaryKey). The reason seems to be that em.find() will also load entity collections, that are annotated with FetchType.LAZY.

This small test case illustrates what I mean:

public class OriginEntityTest4 {

    [..]    

    @Test
    public void test() throws Exception {
    final OriginEntity oe = new OriginEntity("o");
    final ReferencePeakEntity rpe = new ReferencePeakEntity();
    oe.getReferencePeaks().add(rpe);
    DatabaseAccess.onEntityManager(em -> {
        em.persist(oe);
        em.persist(rpe);
    });
    System.out.println(rpe.getEntityId());
    DatabaseAccess.onEntityManager(em -> {
        em.find(OriginEntity.class, oe.getEntityId());
    });

    }

}

@Access(AccessType.PROPERTY)
@Entity(name = "Origin")
public class OriginEntity extends NamedEntity {

    [..]

    private final ListProperty<ReferencePeakEntity> referencePeaks =
    referencePeaks =
    new SimpleListProperty<>(FXCollections.observableArrayList(ReferencePeakEntity.extractor()));

    @Override
    @OneToMany(mappedBy = "origin", fetch = FetchType.LAZY)
    public final List<ReferencePeakEntity> getReferencePeaks() {
    return this.referencePeaksProperty().get();
    }

    public final void setReferencePeaks(final List<ReferencePeakEntity> referencePeaks) {
    this.referencePeaksProperty().setAll(referencePeaks);
    }

}

I cannot find any documentation on that, my question is basically how can I prevent the EntityManager from loading the lazy collection?

Why I need em.find()?

I use the following method to decide whether I need to persist a new entity or update an existing one.

public static void mergeOrPersistWithinTransaction(final EntityManager em, final XIdentEntity entity) {

    final XIdentEntity dbEntity = em.find(XIdentEntity.class, entity.getEntityId());
    if (dbEntity == null) {
        em.persist(entity);
    } else {
        em.merge(entity);
    }
    }

Note that OriginEntity is a JavaFX bean, where getter and setter delegate to a ListProperty.

pirho
  • 8,805
  • 12
  • 34
  • 44
kerner1000
  • 2,661
  • 28
  • 46
  • 2
    Your Set method doesn't work well with a lazy field, as it will need to traverse and fetch the collection to add it as a part of the this.referencePeaksProperty().setAll(referencePeaks) method. Why are you not just storing it locally as a List? – Chris Oct 26 '17 at 17:37
  • Thanks so much! This was the problem. I updated the question. Apparently calling `ListProperty.setAll()` will iterate over all elements. – kerner1000 Oct 26 '17 at 17:53

2 Answers2

1

Because FetchType.LAZY is only a hint. Depending on the implementation and how you configured your entity it will be able to do it or not.

onderbewustzijn
  • 835
  • 7
  • 26
1

Not an answer to titles question but maybe to your problem.

You can use also em.getReference(entityClass, primaryKey) in this case. It should be more efficient in your case since it just gets a reference to possibly existing entity.

See When to use EntityManager.find() vs EntityManager.getReference()

On the other hand i think your check is perhaps not needed. You could just persist or merge without check?

See JPA EntityManager: Why use persist() over merge()?

pirho
  • 8,805
  • 12
  • 34
  • 44