All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebeaninternal.server.core.DefaultBeanLoader Maven / Gradle / Ivy

There is a newer version: 15.8.0
Show newest version
package io.ebeaninternal.server.core;

import io.ebean.CacheMode;
import io.ebean.ExpressionList;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.*;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.transaction.DefaultPersistenceContext;

import jakarta.persistence.EntityNotFoundException;
import java.util.List;

import static java.lang.System.Logger.Level.DEBUG;

/**
 * Helper to handle lazy loading and refreshing of beans.
 */
final class DefaultBeanLoader {

  private static final System.Logger log = CoreLog.internal;

  private final DefaultServer server;
  private final boolean onIterateUseExtraTxn;

  DefaultBeanLoader(DefaultServer server) {
    this.server = server;
    this.onIterateUseExtraTxn = server.databasePlatform().useExtraTransactionOnIterateSecondaryQueries();
  }

  void loadMany(LoadManyRequest loadRequest) {
    executeQuery(loadRequest, loadRequest.createQuery(server));
    loadRequest.postLoad();
  }

  void loadMany(BeanCollection bc, boolean onlyIds) {
    loadManyInternal(bc.owner(), bc.propertyName(), false, onlyIds);
  }

  void refreshMany(EntityBean parentBean, String propertyName) {
    loadManyInternal(parentBean, propertyName, true, false);
  }

  private void loadManyInternal(EntityBean parentBean, String propertyName, boolean refresh, boolean onlyIds) {
    EntityBeanIntercept ebi = parentBean._ebean_getIntercept();
    PersistenceContext pc = ebi.persistenceContext();
    BeanDescriptor parentDesc = server.descriptor(parentBean.getClass());
    BeanPropertyAssocMany many = (BeanPropertyAssocMany) parentDesc.beanProperty(propertyName);
    BeanCollection beanCollection = null;
    ExpressionList filterMany = null;

    Object currentValue = many.getValue(parentBean);
    if (currentValue instanceof BeanCollection) {
      beanCollection = (BeanCollection) currentValue;
      filterMany = beanCollection.filterMany();
    }

    Object parentId = parentDesc.getId(parentBean);
    if (pc == null) {
      pc = new DefaultPersistenceContext();
    }
    parentDesc.contextPutIfAbsent(pc, parentId, parentBean);
    boolean useManyIdCache = beanCollection != null && parentDesc.isManyPropCaching() && many.isUseCache();
    if (useManyIdCache) {
      Boolean readOnly = null;
      if (ebi.isReadOnly()) {
        readOnly = Boolean.TRUE;
      }
      final String parentKey = parentDesc.cacheKey(parentId);
      if (parentDesc.cacheManyPropLoad(many, beanCollection, parentKey, readOnly)) {
        return;
      }
    }

    SpiQuery query = server.createQuery(parentDesc.type());
    if (refresh) {
      // populate a new collection
      BeanCollection emptyCollection = many.createEmpty(parentBean);
      many.setValue(parentBean, emptyCollection);
      query.setLoadDescription("refresh", null);
    } else {
      query.setLoadDescription("lazy", null);
    }

    query.select(parentDesc.idBinder().idSelect());
    if (onlyIds) {
      query.fetch(many.name(), many.targetIdProperty());
    } else {
      query.fetch(many.name());
    }
    if (filterMany != null) {
      query.setFilterMany(many.name(), filterMany);
    }

    query.where().idEq(parentId);
    query.setBeanCacheMode(CacheMode.OFF);
    query.setMode(Mode.LAZYLOAD_MANY);
    query.setLazyLoadManyPath(many.name());
    query.setPersistenceContext(pc);
    if (ebi.isReadOnly()) {
      query.setReadOnly(true);
    }
    if (many.hasOrderColumn()) {
      query.orderBy(many.path() + "." +  many.fetchOrderBy());
    }

    server.findOne(query);
    if (beanCollection != null) {
      if (beanCollection.checkEmptyLazyLoad()) {
        if (log.isLoggable(DEBUG)) {
          log.log(DEBUG, "BeanCollection after load was empty. Owner:{0}", beanCollection.owner());
        }
      } else if (useManyIdCache) {
        final String parentKey = parentDesc.cacheKey(parentId);
        parentDesc.cacheManyPropPut(many, beanCollection, parentKey);
      }
    }
  }

  /**
   * Load a batch of beans for +query or +lazy loading.
   */
  void loadBean(LoadBeanRequest loadRequest) {
    if (loadRequest.checkEmpty()) {
      throw new RuntimeException("Nothing in batch?");
    }
    final SpiQuery query = loadRequest.createQuery(server);
    loadRequest.postLoad(executeQuery(loadRequest, query));
  }

  /**
   * Execute the lazy load query taking into account MySql transaction oddness.
   */
  private List executeQuery(LoadRequest loadRequest, SpiQuery query) {
    if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) {
      // MySql - we need a different transaction to execute the secondary query
      SpiTransaction extraTxn = server.createReadOnlyTransaction(query.tenantId(), query.isUseMaster());
      try {
        query.usingTransaction(extraTxn);
        return server.findList(query);
      } finally {
        extraTxn.end();
      }
    } else {
      return server.findList(query);
    }
  }

  public void refresh(EntityBean bean) {
    refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN, -1);
  }

  void loadBean(EntityBeanIntercept ebi) {
    refreshBeanInternal(ebi.owner(), SpiQuery.Mode.LAZYLOAD_BEAN, -1);
  }

  private void refreshBeanInternal(EntityBean bean, SpiQuery.Mode mode, int embeddedOwnerIndex) {
    EntityBeanIntercept ebi = bean._ebean_getIntercept();
    PersistenceContext pc = ebi.persistenceContext();
    if (Mode.REFRESH_BEAN == mode) {
      // need a new PersistenceContext for REFRESH
      pc = null;
    }
    BeanDescriptor desc = server.descriptor(bean.getClass());
    if (EntityType.EMBEDDED == desc.entityType()) {
      // lazy loading on an embedded bean property
      EntityBean embeddedOwner = (EntityBean) ebi.embeddedOwner();
      refreshBeanInternal(embeddedOwner, mode, ebi.embeddedOwnerIndex());
    }
    Object id = desc.getId(bean);
    if (pc == null) {
      // a reference with no existing persistenceContext
      pc = new DefaultPersistenceContext();
      desc.contextPut(pc, id, bean);
      ebi.setPersistenceContext(pc);
    }
    if (embeddedOwnerIndex == -1) {
      if (desc.lazyLoadMany(ebi)) {
        return;
      }
      if (Mode.LAZYLOAD_BEAN == mode && desc.isBeanCaching()) {
        // lazy loading and the bean cache is active
        if (desc.cacheBeanLoad(bean, ebi, id, pc)) {
          return;
        }
      }
    }
    SpiQuery query = server.createQuery(desc.type());
    query.setLazyLoadProperty(ebi.lazyLoadProperty());
    if (mode == SpiQuery.Mode.LAZYLOAD_BEAN && desc.isSoftDelete()) {
      query.setIncludeSoftDeletes();
    }
    if (embeddedOwnerIndex > -1) {
      query.select(ebi.property(embeddedOwnerIndex));
    }
    // don't collect AutoTune usage profiling information
    // as we just copy the data out of these fetched beans
    // and put the data into the original bean
    query.setUsageProfiling(false);
    query.setPersistenceContext(pc);
    query.setMode(mode);
    query.setId(id);
    if (embeddedOwnerIndex > -1 || mode == Mode.REFRESH_BEAN) {
      // make sure the query doesn't use the cache
      query.setBeanCacheMode(CacheMode.OFF);
    }
    if (ebi.isReadOnly()) {
      query.setReadOnly(true);
    }
    if (Mode.REFRESH_BEAN == mode) {
      // explicitly state to load all properties on REFRESH.
      // Lobs default to fetch lazy so this forces lobs to be
      // included in a 'refresh' query
      query.select("*");
    }

    Object dbBean = query.findOne();
    if (dbBean == null) {
      throw new EntityNotFoundException("Bean not found during lazy load or refresh. Id:" + id + " type:" + desc.type());
    }
    desc.resetManyProperties(dbBean);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy