Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » FetchType.EAGER not always loaded eagerly
FetchType.EAGER not always loaded eagerly [message #1748459] Wed, 23 November 2016 10:34
Benjamin Ellenberger is currently offline Benjamin EllenbergerFriend
Messages: 3
Registered: April 2015
Junior Member
Hello everyone!

We are facing a strange problem occurring within our application using eclipselink. We built a multi-tenancy application which keeps several tenants within one table, separated by a tenancy row. The tenant and a separate entityid form the composite key for each entry. We configured the shared cache and everything works well for most of the time. However, sooner or later while using the application, we face situations where eager loading of related entities does not always work properly. The problem is shown in the following example:

The application loads macroallocations by the id of another entity:

    @Entity
    @Multitenant(value=MultitenantType.SINGLE_TABLE)
    @TenantDiscriminatorColumn(name = DatabaseBindingIds.MACROALLOCATION_TENANT, contextProperty = MULTITENANT_PROPERTY_DEFAULT, primaryKey = true)
    @Cache(type=CacheType.SOFT,size=100000)
    public class MacroAllocation extends ReadWriteRecord {

    	/**
    	* The entity id of this macroallocation.
    	*/
    	@Id
    	@Column(name=DatabaseBindingIds.MACROALLOCATION_ID)
    	private String entityId;

    	/**
    	 * The phase this macroallocation belongs to.
    	 */
    	@ManyToOne(fetch=FetchType.EAGER, optional=false)
    	//@BatchFetch(BatchFetchType.JOIN)
    	@JoinColumn(name=DatabaseBindingIds.MACROALLOCATION_PHASE_ID,referencedColumnName=DatabaseBindingIds.PHASE_ID, insertable=true, updatable=true)
    	private Phase phase;

    	/**
    	 * The resource this macroallocation is assigned to.
    	 */
    	@ManyToOne(fetch=FetchType.EAGER, optional=false)
    	//@BatchFetch(BatchFetchType.JOIN)
    	@JoinColumn(name=DatabaseBindingIds.MACROALLOCATION_RESOURCE_ID, referencedColumnName=DatabaseBindingIds.RESOURCE_ID, insertable=true, updatable=true)
    	private Resource resource;

    	/**
    	 * The duration of the allocation.
    	 */
    	@Column
    	@Convert(converter = DurationConverter.class)
    	private Duration duration;

    	/**
    	 * Get the macroallocation id.
    	 * @exception IllegalStateException EntityId can never be null.
    	 */
    	@Override
    	public String getId() {
        if(entityId == null){
        	throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
        }
        return entityId;
    	}

    	/**
    	 * Set the full id of this macroallocation.
    	 * @exception IllegalStateException EntityId can never be null.
    	 */
    	@Override
    	public void setId(String entityId) {
        markNew();
        this.entityId = entityId;

        if(entityId == null){
        	throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
        }
    	}

    	/**
    	 * Get the phase to which the macroallocation belongs.
    	 * @exception IllegalStateException Phase can never be null.
    	 */
    	public Phase getPhase() {
        if(phase == null){
        	throw new IllegalStateException("[Constraint violation] phase can not be null in " + this.getClass().getSimpleName());
        }
        return phase;
    	}

    	/**
    	 * Set the phase to which the macroallocation belongs.
    	 * @exception IllegalStateException Phase can never be null.
    	 */
    	public void setPhase(Phase x) {
        phase = x;

        if(phase == null){
        	throw new IllegalStateException("[Constraint violation] phase can not be null in " + this.getClass().getSimpleName());
        }
    	}

    	/**
    	 * Get the resource this macroallocation is assigned to.
    	 * @exception IllegalStateException Resource can never be null.
    	 */
    	public Resource getResource() {
        if(resource == null){
        	throw new IllegalStateException("[Constraint violation] resource can not be null in " + this.getClass().getSimpleName());
        }
        return resource;
    	}

    	/**
    	 * Set the resource this macroallocation is assigned to.
    	 * @exception IllegalStateException Resource can never be null.
    	 */
    	public void setResource(Resource x) {
        resource = x;

        if(resource == null){
        	throw new IllegalStateException("[Constraint violation] resource can not be null in " + this.getClass().getSimpleName());
        }
    	}

    	/**
    	 * Get the duration of this macroallocation.
    	 * @return duration - can be null.
    	 */
    	public Duration getDuration() {
        return duration;
    	}

    	/**
    	 * Set the duration of this macroallocation.
    	 * @param duration - can be null.
    	 */
    	public void setDuration(Duration x) {
        duration = x;
    	}
    }


To populate our application layer object based on the database layer entities, we usually get more information from related entities the following way:

macroAllocation.getPhase().getScenario().getProject().getId()

The phase should be eagerly loaded with the macroallocation and the scenario should be eagerly loaded as can be seen in the definition of the phase below:

    @Entity
    @Multitenant(value=MultitenantType.SINGLE_TABLE)
    @TenantDiscriminatorColumn(name = DatabaseBindingIds.PHASE_TENANT, contextProperty = MULTITENANT_PROPERTY_DEFAULT, primaryKey = true)
    @Cache(type=CacheType.SOFT,size=10000)
    public class Phase extends ReadWriteRecord {

    	/**
    	* The entity id of this phase.
    	*/
    	@Id
    	@Column(name=DatabaseBindingIds.PHASE_ID)
    	private String entityId;

    	@OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
    	@BatchFetch(BatchFetchType.JOIN)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.PROPERTYSET_ID, insertable=false, updatable=false)
    	private PropertySet propertySet;

    	@OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
    	@BatchFetch(BatchFetchType.JOIN)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.LOGSET_ID, insertable=false, updatable=false)
    	private LogSet logSet;

    	@OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
    	@BatchFetch(BatchFetchType.JOIN)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.COSTSSET_ID, insertable=false, updatable=false)
    	private CostsSet costsSet;

    	@OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
    	@BatchFetch(BatchFetchType.JOIN)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.TODOSET_ID, insertable=false, updatable=false)
    	private TodoSet todoSet;

    	@ManyToOne(fetch=FetchType.EAGER, optional=false)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_SCENARIO_ID, referencedColumnName=DatabaseBindingIds.SCENARIO_ID, insertable=true, updatable=true)
    	private Scenario scenario;

    	@ManyToOne(fetch=FetchType.EAGER)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_PARENTPHASE_ID, referencedColumnName=DatabaseBindingIds.PHASE_ID, insertable=true, updatable=true)
    	private Phase parentPhase;

    	@Column
    	private Double sortIndex;

    	@Column
    	private String name;

    	@Column
    	private String description;

    	@Column
    	private String imageUrl;

    	@Column
    	@Convert(converter = DurationConverter.class)
    	private Duration budget;

    	@Column
    	@Convert(converter = DurationConverter.class)
    	private Duration planned;

    	@Column
    	@Convert(converter = PointInTimeConverter.class)
    	private PointInTime.Utc beg;

    	@Column//(name="\"End\"") // If you think you want to add this, check first why they are not escaped by the EclipseLink SessionCustomizer
    	@Convert(converter = PointInTimeConverter.class)
    	private PointInTime.Utc end;

    	@Column
    	private Boolean fixed;

    	@Column
    	private Integer progress;

    	@Column
    	private Boolean autoProgress;

    	@Column
    	private String costCenter;

    	@ManyToOne(fetch=FetchType.LAZY)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_OWNER_ID, referencedColumnName=DatabaseBindingIds.RESOURCE_ID, insertable=true, updatable=true)
    	private Resource owner;

    	@Column
    	private String color;

    	@ManyToOne(fetch=FetchType.LAZY)
    	@JoinColumn(name=DatabaseBindingIds.PHASE_REQUIRED_SKILL_ID, referencedColumnName=DatabaseBindingIds.RESOURCE_ID, insertable=true, updatable=true)
    	private Resource requiredSkill;

    	@OneToMany(mappedBy="fromPhase", fetch=FetchType.LAZY)
    	private List<PhaseDependency> forwardDependencies;

    	@OneToMany(mappedBy="toPhase", fetch=FetchType.LAZY)
    	private List<PhaseDependency> reverseDependencies;

    	/**
    	 * Get the phase id.
    	 * @exception IllegalStateException EntityId can never be null.
    	 */
    	@Override
    	public String getId() {
        if(entityId == null){
        	throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
        }
        return entityId;
    	}

    	/**
    	 * Set the full id of this phase.
    	 * @exception IllegalStateException EntityId can never be null.
    	 */
    	@Override
    	public void setId(String entityId) {
        markNew();
        this.entityId = entityId;

        if(entityId == null){
        	throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
        }

        propertySet = new PropertySet();
        propertySet.setId(entityId);

        logSet = new LogSet();
        logSet.setId(entityId);

        costsSet = new CostsSet();
        costsSet.setId(entityId);

        todoSet = new TodoSet();
        todoSet.setId(entityId);
    	}

    	/**
    	 * Get the property set of the phase.
    	 * @exception IllegalStateException propertySet can never be null.
    	 */
    	public PropertySet getPropertySet() {
        if(propertySet == null){
        	throw new IllegalStateException("[Constraint violation] propertySet can not be null in " + this.getClass().getSimpleName());
        }
        return propertySet;
    	}

    	/**
    	 * Get the log set of the phase.
    	 * @exception IllegalStateException logSet can never be null.
    	 */
    	public LogSet getLogSet() {
        if(logSet == null){
        	throw new IllegalStateException("[Constraint violation] logSet can not be null in " + this.getClass().getSimpleName());
        }
        return logSet;
    	}

    	/**
    	 * Get the costs set of the phase.
    	 * @exception IllegalStateException costsSet can never be null.
    	 */
    	public CostsSet getCostsSet() {
        if(costsSet == null){
        	throw new IllegalStateException("[Constraint violation] costsSet can not be null in " + this.getClass().getSimpleName());
        }
        return costsSet;
    	}

    	/**
    	 * Get the todo set of the phase.
    	 * @exception IllegalStateException todoSet can never be null.
    	 */
    	public TodoSet getTodoSet() {
        if(todoSet == null){
        	throw new IllegalStateException("[Constraint violation] todoSet can not be null in " + this.getClass().getSimpleName());
        }
        return todoSet;
    	}

    	/**
    	 * Get the scenario of the phase.
    	 * @exception IllegalStateException scenario can never be null.
    	 */
    	public Scenario getScenario() {
        if(scenario == null){
        	throw new IllegalStateException("[Constraint violation] scenario can not be null in " + this.getClass().getSimpleName());
        }
        return scenario;
    	}

    	/**
    	 * Set the scenario of the phase.
    	 * @exception IllegalStateException scenario can never be null.
    	 */
    	public void setScenario(Scenario x) {
        scenario = x;

        if(scenario == null){
        	throw new IllegalStateException("[Constraint violation] scenario can not be null in " + this.getClass().getSimpleName());
        }
    	}

    	/**
    	 * Get the parent phase of this phase.
    	 * @return parentPhase - can be null.
    	 */
    	public Phase getParentPhase() {
        return parentPhase;
    	}

    	/**
    	 * Set the parent phase of this phase.
    	 * @return parentPhase - can be null.
    	 */
    	public void setParentPhase(Phase x) {
        parentPhase = x;
    	}

    	/**
    	 * Get the sort index of the phase.
    	 * @return
    	 */
    	public double getSortIndex() {
        return sortIndex == null ? 0.0 : sortIndex;
    	}

    	/**
    	 * Set the sort index of the phase.
    	 * @param x
    	 */
    	public void setSortIndex(double x) {
        sortIndex = x;
    	}

    	/**
    	 * Get the name of the phase.
    	 * @return name - can be null.
    	 */
    	public String getName() {
        return name;
    	}

    	/**
    	 * Set the name of this phase.
    	 * @param name - can be null.
    	 */
    	public void setName(String x) {
        name = x;
    	}

    	/**
    	 * Get the description of the phase.
    	 * @return description - can be null.
    	 */
    	public String getDescription() {
        return description;
    	}

    	/**
    	 * Set the description of this phase.
    	 * @param description - can be null.
    	 */
    	public void setDescription(String x) {
        description = x;
    	}

    	/**
    	 * Get the image url of the phase.
    	 * @return imageUrl - can be null.
    	 */
    	public String getImageUrl() {
        return imageUrl;
    	}

    	/**
    	 * Set the imag url of this phase.
    	 * @param imageUrl - can be null.
    	 */
    	public void setImageUrl(String x) {
        imageUrl = x;
    	}

    	/**
    	 * Get the budget of the phase.
    	 * @return budget - can be null.
    	 */
    	public Duration getBudget() {
        return budget;
    	}

    	/**
    	 * Set the budget of this phase.
    	 * @param budget - can be null.
    	 */
    	public void setBudget(Duration x) {
        budget = x;
    	}

    	/**
    	 * Get the planned duration of the phase.
    	 * @return planned - can be null.
    	 */
    	public Duration getPlanned() {
        return planned;
    	}

    	/**
    	 * Set the planned duration of this phase.
    	 * @param planned - can be null.
    	 */
    	public void setPlanned(Duration x) {
        planned = x;
    	}

    	/**
    	 * Get the beginning of the phase.
    	 * @return beg - can be null.
    	 */
    	public PointInTime.Utc getBeg() {
        return beg;
    	}

    	/**
    	 * Set the beginning of this phase.
    	 * @param beg - can be null.
    	 */
    	public void setBeg(PointInTime.Utc x) {
        beg = x;
    	}

    	/**
    	 * Get the ending of the phase.
    	 * @return end - can be null.
    	 */
    	public PointInTime.Utc getEnd() {
        return end;
    	}

    	/**
    	 * Set the ending of this phase.
    	 * @param end - can be null.
    	 */
    	public void setEnd(PointInTime.Utc x) {
        end = x;
    	}

    	/**
    	 * Get if the phase is fixed.
    	 * @return
    	 */
    	public boolean getFixed() {
        return fixed == null ? false : fixed;
    	}

    	/**
    	 * Set if the phase is fixed.
    	 * @param x
    	 */
    	public void setFixed(boolean x) {
        fixed = x;
    	}

    	/**
    	 * Get the progress of the phase.
    	 * @return
    	 */
    	public int getProgress() {
        return progress == null ? 0 : progress;
    	}

    	/**
    	 * Set the progress of this phase.
    	 * @param
    	 */
    	public void setProgress(int x) {
        progress = x;
    	}

    	/**
    	 * Get if the phase progresses automatically.
    	 * @exception IllegalStateException autoProgress can never be null.
    	 */
    	public boolean getAutoProgress() {
        return autoProgress == null ? false : autoProgress;
    	}

    	/**
    	 * Get if the phase progresses automatically.
    	 * @exception IllegalStateException autoProgress can never be null.
    	 */
    	public void setAutoProgress(boolean x) {
        autoProgress = x;
    	}

    	... not relevant getters and setters...
    }



To get proper exceptions when our problem occurs, we added IllegalStateExceptions being thrown that tell us similarly to the db constraints, that an eager loading constraint has been violated. When the problem occurs, we get:

java.lang.IllegalStateException: [Constraint violation] scenario can not be null in Phase

This means that during the loading of the macroallocation, the scenario was not loaded.

The only workaround we found is by accessing the scenario while the database session is still open, but from our understanding, this should only be necessary to load lazy loaded entity relations. What could the problem be? Below are the macroallocation loading method:

	@Override
    public List<MacroAllocation> loadMacroAllocationsByResource(String resourceId) throws DataAccessException {
        try(DatabaseSession session = new DatabaseSession(tenant)) {
            List<MacroAllocation> macroAllocations = session.loadByQuery(MacroAllocation.class,
                    "SELECT ma FROM MacroAllocation AS ma "
                    + "WHERE ma.resource.entityId = ?1 " // with matching primary key in resource
                    + "AND ma.deleted = 0", // and not deleted
                    resourceId);
            
            //Workaround: Some objects are not eagerly fetched in some cases. Here we do that explicitly.
            macroAllocations.stream().forEach((m) -> {
            	session.fetch(m.getPhase().getScenario());
            	session.fetch(m.getPhase().getScenario().getProject());
            });

            return macroAllocations;
        } catch(RuntimeException e) {
            throw new DataAccessException(e);
        }
	}



and the database session we use within this method:

    public final class DatabaseSession implements AutoCloseable {

    	/**
    	 * Maximum latency in milliseconds for a JPA operation, after which a warning shall be logged.
    	 */
    	private static final double MAX_LATENCY = 100.0;

    	/**
    	 * Maximum duration in milliseconds for a session, after which a warning shall be logged.
    	 */
    	private static final double MAX_LATENCY_TOT = 1000.0;

    	/**
    	 * Our logger, never null.
    	 */
    	private static final Logger log = LoggerFactory.getLogger(DatabaseSession.class);

    	/**
    	 * The factory for creating EntityManager instances, created in initEntityManagerFactory() or in the constructor.
    	 */
    	private static String persistenceUnitName;

    	/**
    	 * The EntityManager instance to access the database, created from the factory in the constructor.
    	 */
    	private EntityManager em;

    	/**
    	 * The time when the instance was created, useful for measure total time of the session.
    	 */
    	private final long ttot = System.nanoTime();

    	/**
    	 * Indicates whether commit() as been called.
    	 */
    	private boolean committed;

    	private String tenant;

    	private static final Cache<String, EntityManagerFactory> emfs = new Cache<>(tenant -> { // create if absent
        synchronized (DatabaseSession.class) {
        	HashMap<String,String> properties = new HashMap<>();
        	properties.put(SESSION_NAME, (tenant!=null && tenant != "")?tenant+"-session":"non-tenant-session");
        	properties.put(MULTITENANT_PROPERTY_DEFAULT, tenant);

        	if(persistenceUnitName == null){
            log.debug("Persistence Unit Name defaults to: default");
            persistenceUnitName = "default";
        	}
        	return Persistence.createEntityManagerFactory(persistenceUnitName, properties);
        }
    	},
    	(entityManagerFactory) -> { // on remove
        entityManagerFactory.close();
    	});

    	/**
    	 * Opens a new non-tenant specific session and begins a new transaction.
    	 *
    	 * Only shared, non-tenant specific entities can be retrieved. Multitenancy entities can not be retrieved using this session. To retrieve tenant specific entities, create a tenant session using <b>new DataSession(tenant)</b>
    	 */
    	public DatabaseSession() {
        this.tenant = "";
        synchronized (DatabaseSession.class) {
        	emfs.get(tenant);
        }
        createEntityManager();
    	}

    	/**
    	 * Opens a new tenant session and begins a new transaction.
    	 *
    	 * Multitenancy entities can be retrieved using this session.
    	 */
    	public DatabaseSession(String tenant) {
        if(tenant == null || tenant.equals("")){
        	log.error("Trying to create a non-tenant database session with tenant specific constructor? Use constructor DatabaseSession() instead.");
        	tenant = "";
        }
        this.tenant = tenant;
        synchronized (DatabaseSession.class) {
        	emfs.get(tenant); // creates a new factory in a synchronized manner.
        }
        createEntityManager();
    	}

    	/**
    	 * @note: Should only be called publicly by unit tests.
    	 */
    	public void createEntityManager() {
        em = emfs.get(tenant).createEntityManager();
        em.getTransaction().begin();
    	}

    	/**
    	 * Initializes the EntityManagerFactory (optional, useful for testing).
    	 * <p>
    	 * If this method is not called, the EntityManagerFactory is initialized automatically with persistence unit "default" when the first instance is created.
    	 * <p>
    	 * Persistence units are defined in conf/META-INF/persistence.xml.
    	 *
    	 * @param persistenceUnitName
    	 *            the name of the persistence unit to be used, must match the XML attribute /persistence/persistence-unit/@name.
    	 */
    	public static void initEntityManagerFactory(String pun) {
    	   persistenceUnitName = pun;
    	}

    	/**
    	 * Sets up all factories to prevent eclipselink from drop and creating the db.
    	 *
    	 * @note: Should only be called by unit tests.
    	 */
    	public void setupEntityManagerFactories(List<String> tenants) {
        log.warn("SetupEntityManagerFactories should only be called by Unit tests.");
        for(String tenant: tenants){
        	emfs.get(tenant);
        }
    	}

    	/**
    	 * Closes the connection to the database completely. For Unit tests, this drops and recreates the database to advance to the next unit test with a fresh one.
    	 *
    	 * @note: Should only be called by unit tests.
    	 */
    	public void shutdownDB() {
        log.warn("ShutdownDB should only be called by Unit tests.");
        em.close();
        em = null;
        DatabaseSession.emfs.clear(); // closes entity manager factory on close
    	}

    	@Override
    	public void close() {
        try {
        	if (!committed) {
            if (em != null) {
            	em.getTransaction().rollback();
            }
        	}
        } finally {
        	if (committed) {
            if (em != null) {
            	em.close();
            }
        	}

        	double latency = (System.nanoTime() - ttot) / 1000000.0;
        	if (latency > MAX_LATENCY_TOT) {
            log.warn("Duration of session was " + latency + "ms.");
        	} else {
            log.debug("Duration of session was " + latency + "ms.");
        	}
        }
    	}

    	/**
    	 * Commits the transaction, must explicitly be done before the session is closed.
    	 */
    	public void commit() {
        long t = System.nanoTime();
        em.flush();
        em.getTransaction().commit();
        committed = true;
        double latency = (System.nanoTime() - t) / 1000000.0;
        if (latency > MAX_LATENCY) {
        	warn("Latency of commit() was %sms.", latency);
        }
    	}

    	public <T extends PersistentRecord> List<T> loadAll(Class<T> clazz) {
        return loadAll(clazz, true);
    	}

    	public <T extends PersistentRecord> List<T> loadAll(Class<T> clazz, boolean filterDeleted) {
        log("loadAll(%s)", clazz.getSimpleName());
        long t = System.nanoTime();
        CriteriaBuilder b = em.getCriteriaBuilder();
        CriteriaQuery<T> q = b.createQuery(clazz);
        Metamodel m = em.getMetamodel();
        EntityType<T> et = m.entity(clazz);
        Root<T> r = q.from(clazz);
        q.select(r);

        if (filterDeleted) {
        	q.where(b.equal(r.get(et.getAttribute("deleted").getName()), 0));
        }
        List<T> results = em.createQuery(q).getResultList();

        double latency = (System.nanoTime() - t) / 1000000.0;
        if (latency > MAX_LATENCY) {
        	warn("Latency of loadAll(%s) was %sms.", clazz.getSimpleName(), latency);
        }
        return results;
    	}

    	public <T extends PersistentRecord> int count(Class<T> clazz) {
        return count(clazz, true);
    	}

    	public <T extends PersistentRecord> int count(Class<T> clazz, boolean filterDeleted) {
        log("count(%s)", clazz.getSimpleName());
        long t = System.nanoTime();
        CriteriaBuilder b = em.getCriteriaBuilder();
        CriteriaQuery<T> q = b.createQuery(clazz);
        Metamodel m = em.getMetamodel();
        EntityType<T> et = m.entity(clazz);
        Root<T> r = q.from(clazz);
        q.select(r);

        if (filterDeleted) {
        	q.where(b.equal(r.get(et.getAttribute("deleted").getName()), 0));
        }

        List<T> result = em.createQuery(q).getResultList();
        double latency = (System.nanoTime() - t) / 1000000.0;
        if (latency > MAX_LATENCY) {
        	warn("Latency of count(%s) was %sms.", clazz.getSimpleName(), latency);
        }
        return result.size();
    	}

    	public <T extends PersistentRecord> T load(Class<T> clazz, String id) {
        return load(clazz, id, true);
    	}

    	public <T extends PersistentRecord> T load(Class<T> clazz, String id, boolean filterDeleted) {
        log("load(%s, %s)", clazz.getSimpleName(), id);
        long t = System.nanoTime();
        T result = em.find(clazz, id);
        if (filterDeleted) {
        	result = filterDeleted(result);
        }
        double latency = (System.nanoTime() - t) / 1000000.0;
        if (latency > MAX_LATENCY) {
        	warn("Latency of load(%s, %s) was %sms.", clazz.getSimpleName(), id, latency);
        }
        return result;
    	}

    	public <T extends PersistentRecord> List<T> loadByQuery(Class<T> clazz, String query, Object... params) {
        log("loadByQuery(%s, '%s', %s)", clazz.getSimpleName(), query, format(params));
        long t = System.nanoTime();
        TypedQuery<T> q = em.createQuery(query, clazz);
        for (int i = 0; i < params.length; i++) {
        	q.setParameter(i + 1, params[i]);
        }
        List<T> result = q.getResultList();
        result = filterDeleted(result);
        double latency = (System.nanoTime() - t) / 1000000.0;
        if (latency > MAX_LATENCY) {
        	warn("Latency of loadByQuery(%s, '%s', %s) was %sms.", clazz.getSimpleName(), query, format(params), latency);
        }
        return result;
    	}

    	public <T extends PersistentRecord> T loadSingleByQuery(Class<T> clazz, String query, Object... params) {
        log("loadSingleByQuery(%s, '%s', %s)", clazz.getSimpleName(), query, format(params));
        long t = System.nanoTime();
        TypedQuery<T> q = em.createQuery(query, clazz);
        for (int i = 0; i < params.length; i++) {
        	q.setParameter(i + 1, params[i]);
        }
        List<T> result = q.getResultList();
        result = filterDeleted(result);
        double latency = (System.nanoTime() - t) / 1000000.0;
        if (latency > MAX_LATENCY) {
        	warn("Latency of loadSingleByQuery(%s, '%s', %s) was %sms.", clazz.getSimpleName(), query, format(params), latency);
        }
        return result.size() > 0 ? result.get(0) : null;
    	}

    	... storing methods not relevant here...
    }


Tell me anything you are missing from this post and I will add it.

[Updated on: Wed, 23 November 2016 10:39]

Report message to a moderator

Previous Topic:FetchType.EAGER not always loaded eagerly
Next Topic:EclipseLink can't create foreign key constraints
Goto Forum:
  


Current Time: Wed Dec 13 16:59:05 GMT 2017

Powered by FUDForum. Page generated in 0.02000 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software