public void checkVersionAndRaiseSOSE(
     Serializable id, Object oldVersion, SessionImplementor session, Tuple resultset) {
   final Object resultSetVersion =
       gridVersionType.nullSafeGet(resultset, getVersionColumnName(), session, null);
   final SessionFactoryImplementor factory = getFactory();
   if (!gridVersionType.isEqual(oldVersion, resultSetVersion, factory)) {
     if (factory.getStatistics().isStatisticsEnabled()) {
       factory.getStatisticsImplementor().optimisticFailure(getEntityName());
     }
     throw new StaleObjectStateException(getEntityName(), id);
   }
 }
 private Tuple createNewResultSetIfNull(
     EntityKey key, Tuple resultset, Serializable id, SessionImplementor session) {
   if (resultset == null) {
     resultset = gridDialect.createTuple(key, getTupleContext());
     gridIdentifierType.nullSafeSet(resultset, id, getIdentifierColumnNames(), session);
   }
   return resultset;
 }
  /** Retrieve the version number */
  @Override
  public Object getCurrentVersion(Serializable id, SessionImplementor session)
      throws HibernateException {

    if (log.isTraceEnabled()) {
      log.trace("Getting version: " + MessageHelper.infoString(this, id, getFactory()));
    }
    final Tuple resultset = getResultsetById(id, session);

    if (resultset == null) {
      return null;
    } else {
      return gridVersionType.nullSafeGet(resultset, getVersionColumnName(), session, null);
    }
  }
  @Override
  public Object forceVersionIncrement(
      Serializable id, Object currentVersion, SessionImplementor session) {
    if (!isVersioned()) {
      throw new AssertionFailure("cannot force version increment on non-versioned entity");
    }

    if (isVersionPropertyGenerated()) {
      // the difficulty here is exactly what do we update in order to
      // force the version to be incremented in the db...
      throw new HibernateException(
          "LockMode.FORCE is currently not supported for generated version properties");
    }

    Object nextVersion = getVersionType().next(currentVersion, session);
    if (log.isTraceEnabled()) {
      log.trace(
          "Forcing version increment ["
              + MessageHelper.infoString(this, id, getFactory())
              + "; "
              + getVersionType().toLoggableString(currentVersion, getFactory())
              + " -> "
              + getVersionType().toLoggableString(nextVersion, getFactory())
              + "]");
    }

    /*
     * We get the value from the grid and compare the version values before putting the next version in
     * Contrary to the database version, there is
     * TODO should we use cache.replace() it seems more expensive to pass the resultset around "just" the atomicity of the operation
     */
    final EntityKey key = EntityKeyBuilder.fromPersister(this, id, session);
    final Tuple resultset = gridDialect.getTuple(key, getTupleContext());
    checkVersionAndRaiseSOSE(id, currentVersion, session, resultset);
    gridVersionType.nullSafeSet(
        resultset, nextVersion, new String[] {getVersionColumnName()}, session);
    gridDialect.updateTuple(resultset, key, getTupleContext());
    return nextVersion;
  }
  @Override
  public void delete(Serializable id, Object version, Object object, SessionImplementor session)
      throws HibernateException {
    final int span = getTableSpan();
    if (span > 1) {
      throw new HibernateException(
          "Hibernate OGM does not yet support entities spanning multiple tables");
    }
    final EntityMetamodel entityMetamodel = getEntityMetamodel();
    boolean isImpliedOptimisticLocking = !entityMetamodel.isVersioned() && isAllOrDirtyOptLocking();
    Object[] loadedState = null;
    if (isImpliedOptimisticLocking) {
      // need to treat this as if it where optimistic-lock="all" (dirty does *not* make sense);
      // first we need to locate the "loaded" state
      //
      // Note, it potentially could be a proxy, so doAfterTransactionCompletion the location the
      // safe way...
      org.hibernate.engine.spi.EntityKey key = session.generateEntityKey(id, this);
      Object entity = session.getPersistenceContext().getEntity(key);
      if (entity != null) {
        EntityEntry entry = session.getPersistenceContext().getEntry(entity);
        loadedState = entry.getLoadedState();
      }
    }

    final EntityKey key = EntityKeyBuilder.fromPersister(this, id, session);
    final Tuple resultset = gridDialect.getTuple(key, this.getTupleContext());
    final SessionFactoryImplementor factory = getFactory();
    if (isImpliedOptimisticLocking && loadedState != null) {
      // we need to utilize dynamic delete statements
      for (int j = span - 1; j >= 0; j--) {
        boolean[] versionability = getPropertyVersionability();

        // TODO do a diff on the properties value from resultset
        GridType[] types = gridPropertyTypes;

        for (int i = 0; i < entityMetamodel.getPropertySpan(); i++) {
          boolean include = isPropertyOfTable(i, j) && versionability[i];
          if (include) {
            final GridType type = types[i];
            final Object snapshotValue =
                type.nullSafeGet(resultset, getPropertyColumnNames(i), session, object);
            // TODO support other entity modes
            if (!type.isEqual(loadedState[i], snapshotValue, factory)) {
              if (factory.getStatistics().isStatisticsEnabled()) {
                factory.getStatisticsImplementor().optimisticFailure(getEntityName());
              }
              throw new StaleObjectStateException(getEntityName(), id);
            }
          }
        }
      }
    } else {
      if (entityMetamodel.isVersioned()) {
        checkVersionAndRaiseSOSE(id, version, session, resultset);
      }
    }

    for (int j = span - 1; j >= 0; j--) {
      if (isInverseTable(j)) {
        return;
      }
      if (log.isTraceEnabled()) {
        log.trace("Deleting entity: " + MessageHelper.infoString(this, id, factory));
        if (j == 0 && isVersioned()) {
          log.trace("Version: " + version);
        }
      }

      // delete association information
      // needs to be executed before the tuple removal because the AtomicMap in ISPN is cleared upon
      // removal
      new EntityDehydrator()
          .gridDialect(gridDialect)
          .gridPropertyTypes(gridPropertyTypes)
          .gridIdentifierType(gridIdentifierType)
          .id(id)
          .persister(this)
          .resultset(resultset)
          .session(session)
          .tableIndex(j)
          .onlyRemovePropertyMetadata()
          .dehydrate();

      gridDialect.removeTuple(key, getTupleContext());
    }
  }
  /** Update an object */
  @Override
  public void update(
      final Serializable id,
      final Object[] fields,
      final int[] dirtyFields,
      final boolean hasDirtyCollection,
      final Object[] oldFields,
      final Object oldVersion,
      final Object object,
      final Object rowId,
      final SessionImplementor session)
      throws HibernateException {

    // note: dirtyFields==null means we had no snapshot, and we couldn't get one using
    // select-before-update
    //	  oldFields==null just means we had no snapshot to begin with (we might have used
    // select-before-update to get the dirtyFields)

    // TODO support "multi table" entities
    final boolean[] tableUpdateNeeded = getTableUpdateNeeded(dirtyFields, hasDirtyCollection);
    final int span = getTableSpan();

    final boolean[] propsToUpdate;
    EntityEntry entry = session.getPersistenceContext().getEntry(object);

    // Ensure that an immutable or non-modifiable entity is not being updated unless it is
    // in the process of being deleted.
    if (entry == null && !isMutable()) {
      throw new IllegalStateException("Updating immutable entity that is not in session yet!");
    }
    // we always use a dynamicUpdate model for Infinispan
    if ((
    // getEntityMetamodel().isDynamicUpdate() &&
    dirtyFields != null)) {

      propsToUpdate = getPropertiesToUpdate(dirtyFields, hasDirtyCollection);
      // don't need to check laziness (dirty checking algorithm handles that)
    } else if (!isModifiableEntity(entry)) {
      // TODO does that apply to OGM?
      // We need to generate UPDATE SQL when a non-modifiable entity (e.g., read-only or immutable)
      // needs:
      // - to have references to transient entities set to null before being deleted
      // - to have version incremented do to a "dirty" association
      // If dirtyFields == null, then that means that there are no dirty properties to
      // to be updated; an empty array for the dirty fields needs to be passed to
      // getPropertiesToUpdate() instead of null.
      propsToUpdate =
          getPropertiesToUpdate(
              (dirtyFields == null ? ArrayHelper.EMPTY_INT_ARRAY : dirtyFields),
              hasDirtyCollection);
      // don't need to check laziness (dirty checking algorithm handles that)
    } else {
      // For the case of dynamic-update="false", or no snapshot, we update all properties
      // TODO handle lazy
      propsToUpdate = getPropertyUpdateability(object);
    }

    final SessionFactoryImplementor factory = getFactory();
    if (log.isTraceEnabled()) {
      log.trace("Updating entity: " + MessageHelper.infoString(this, id, factory));
      if (isVersioned()) {
        log.trace(
            "Existing version: " + oldVersion + " -> New version: " + fields[getVersionProperty()]);
      }
    }

    for (int j = 0; j < span; j++) {
      // Now update only the tables with dirty properties (and the table with the version number)
      if (tableUpdateNeeded[j]) {
        final EntityKey key = EntityKeyBuilder.fromPersister(this, id, session);
        Tuple resultset = gridDialect.getTuple(key, this.getTupleContext());
        final boolean useVersion = j == 0 && isVersioned();

        resultset = createNewResultSetIfNull(key, resultset, id, session);

        final EntityMetamodel entityMetamodel = getEntityMetamodel();

        // Write any appropriate versioning conditional parameters
        if (useVersion && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION) {
          if (checkVersion(propsToUpdate)) {
            checkVersionAndRaiseSOSE(id, oldVersion, session, resultset);
          }
        } else if (isAllOrDirtyOptLocking() && oldFields != null) {
          boolean[] versionability =
              getPropertyVersionability(); // TODO: is this really necessary????
          boolean[] includeOldField =
              entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL
                  ? getPropertyUpdateability()
                  : propsToUpdate;
          // TODO do a diff on the properties value from resultset and the dirty value
          GridType[] types = gridPropertyTypes;

          for (int i = 0; i < entityMetamodel.getPropertySpan(); i++) {
            boolean include =
                includeOldField[i]
                    && isPropertyOfTable(i, j)
                    && versionability[i]; // TODO: is this really necessary????
            if (include) {
              final GridType type = types[i];
              // FIXME what do do with settable?
              boolean[] settable = type.toColumnNullness(oldFields[i], factory);
              final Object snapshotValue =
                  type.nullSafeGet(resultset, getPropertyColumnNames(i), session, object);
              comparePropertyAndRaiseSOSE(
                  id, oldFields[i], factory, !type.isEqual(oldFields, snapshotValue, factory));
            }
          }
        }

        // dehydrate
        dehydrate(resultset, fields, propsToUpdate, getPropertyColumnUpdateable(), j, id, session);
        gridDialect.updateTuple(resultset, key, getTupleContext());
      }
    }
  }