/** Put the beanCollection into the cache. */
  void manyPropPut(BeanPropertyAssocMany<?> many, Object details, Object parentId) {

    CachedManyIds entry = createManyIds(many, details);
    if (entry != null) {
      cachePutManyIds(parentId, many.getName(), entry);
    }
  }
  /** Add appropriate changes to support update. */
  void handleUpdate(Object id, PersistRequestBean<T> updateRequest, CacheChangeSet changeSet) {

    queryCacheClear(changeSet);

    if (beanCache == null) {
      // query caching only
      return;
    }

    List<BeanPropertyAssocMany<?>> manyCollections = updateRequest.getUpdatedManyCollections();
    if (manyCollections != null) {
      for (BeanPropertyAssocMany<?> many : manyCollections) {
        Object details = many.getValue(updateRequest.getEntityBean());
        CachedManyIds entry = createManyIds(many, details);
        if (entry != null) {
          changeSet.addManyPut(desc, many.getName(), id, entry);
        }
      }
    }

    // check if the bean itself was updated
    if (!updateRequest.isUpdatedManysOnly()) {

      boolean updateNaturalKey = false;

      Map<String, Object> changes = new LinkedHashMap<>();
      EntityBean bean = updateRequest.getEntityBean();
      boolean[] dirtyProperties = updateRequest.getDirtyProperties();
      for (int i = 0; i < dirtyProperties.length; i++) {
        if (dirtyProperties[i]) {
          BeanProperty property = desc.propertiesIndex[i];
          if (property.isCacheDataInclude()) {
            Object val = property.getCacheDataValue(bean);
            changes.put(property.getName(), val);
            if (property.isNaturalKey()) {
              updateNaturalKey = true;
              changeSet.addNaturalKeyPut(desc, id, val);
            }
          }
        }
      }

      changeSet.addBeanUpdate(desc, id, changes, updateNaturalKey, updateRequest.getVersion());
    }
  }
  private CachedManyIds createManyIds(BeanPropertyAssocMany<?> many, Object details) {

    BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();

    List<Object> idList = new ArrayList<>();
    Collection<?> actualDetails = BeanCollectionUtil.getActualEntries(details);
    if (actualDetails == null) {
      return null;
    }
    for (Object bean : actualDetails) {
      idList.add(targetDescriptor.getId((EntityBean) bean));
    }
    return new CachedManyIds(idList);
  }
  /** Try to load the bean collection from cache return true if successful. */
  boolean manyPropLoad(
      BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {

    CachedManyIds entry = manyPropGet(parentId, many.getName());
    if (entry == null) {
      // not in cache so return unsuccessful
      return false;
    }

    Object ownerBean = bc.getOwnerBean();
    EntityBeanIntercept ebi = ((EntityBean) ownerBean)._ebean_getIntercept();
    PersistenceContext persistenceContext = ebi.getPersistenceContext();

    BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();

    List<Object> idList = entry.getIdList();
    bc.checkEmptyLazyLoad();
    for (Object id : idList) {
      Object refBean = targetDescriptor.createReference(readOnly, false, id, persistenceContext);
      many.add(bc, (EntityBean) refBean);
    }
    return true;
  }