@SuppressWarnings("unchecked")
  private CriteriaQueryImpl<Y> generateOwnerSelectCriteria(
      final MetamodelImpl metamodel,
      final CriteriaBuilderImpl cb,
      Class<Y> bindableType,
      EntityTypeImpl<Y> entity) {
    final CriteriaQueryImpl<Y> q = cb.createQuery(bindableType);
    q.internal();

    final EntityTypeImpl<?> type = (EntityTypeImpl<?>) this.getRoot().getType();

    final RootImpl<?> r = q.from(type);
    r.alias(BatooUtils.acronym(type.getName()).toLowerCase());

    final Iterator<String> pathIterator = Splitter.on(".").split(this.getPath()).iterator();

    // Drop the root part
    pathIterator.next();

    AbstractJoin<?, ?> join = null;
    while (pathIterator.hasNext()) {
      join = join == null ? r.<Y>join(pathIterator.next()) : join.join(pathIterator.next());
    }

    q.select((Selection<? extends Y>) join);

    entity.prepareEagerJoins(join, 0, this);

    return this.selectCriteria = q.where(cb.equal(r, cb.parameter(type.getJavaType())));
  }
  private CriteriaQueryImpl<Y> generateMappedSelectCriteria(
      MetamodelImpl metamodel,
      CriteriaBuilderImpl cb,
      Class<Y> bindableType,
      EntityTypeImpl<Y> entity) {
    final CriteriaQueryImpl<Y> q = cb.createQuery(bindableType);
    q.internal();

    final RootImpl<Y> r = q.from(entity);
    r.alias(BatooUtils.acronym(entity.getName()).toLowerCase());

    q.select(r);

    final Iterator<String> pathIterator =
        Splitter.on(".").split(this.getInverse().getPath()).iterator();

    // Drop the root part
    pathIterator.next();

    AbstractPath<?> path = null;
    while (pathIterator.hasNext()) {
      path = path == null ? r.get(pathIterator.next()) : path.get(pathIterator.next());
    }

    entity.prepareEagerJoins(r, 0, this);

    final ParameterExpressionImpl<?> pe = cb.parameter(this.getInverse().getJavaType());
    final PredicateImpl predicate = cb.equal(path, pe);
    return this.selectCriteria = q.where(predicate);
  }
  /**
   * @param type the entity type of the instance
   * @param session the session
   * @param instance the instance
   * @param id the id of the instance
   * @since 2.0.0
   */
  public ManagedInstance(
      EntityTypeImpl<X> type, SessionImpl session, X instance, ManagedId<? super X> id) {
    this(type, session, instance);

    type.setId(session, instance, id.getId());

    this.id = id;
  }
  private boolean fillValuesImpl() {
    final EntityTypeImpl<X> _type = this.type;

    if (_type.hasSingleIdAttribute()) {
      return this.type
          .getRootType()
          .getIdMapping()
          .fillValue(_type.getRootType(), this, this.instance);
    } else {
      for (final Pair<SingularMapping<?, ?>, AbstractAccessor> mapping : _type.getIdMappings()) {
        if (!((SingularMappingEx<?, ?>) mapping.getFirst())
            .fillValue(_type.getRootType(), this, this.instance)) {
          return false;
        }
      }

      return true;
    }
  }
  /**
   * Increments the version of the instance.
   *
   * @param connection the connection
   * @param commit true if version update should be committed immediately
   * @throws SQLException thrown in case of an underlying SQL error
   * @since 2.0.0
   */
  public void incrementVersion(Connection connection, boolean commit) throws SQLException {
    if (!this.type.getRootType().hasVersionAttribute()) {
      return;
    }

    final EntityTypeImpl<? super X> rootType = this.type.getRootType();

    final BasicAttribute<? super X, ?> version = rootType.getVersionAttribute();

    if (this.oldVersion == null) {
      switch (this.type.getVersionType()) {
        case SHORT:
          final short shortValue = (((Number) version.get(this.instance)).shortValue());
          this.oldVersion = shortValue;
          version.set(this.instance, shortValue + 1);

          ManagedInstance.LOG.debug("Version upgraded instance: {0} - {1}", this, shortValue);

          break;
        case SHORT_OBJECT:
          final Short shortObjValue =
              version.get(this.instance) == null
                  ? 0
                  : //
                  Short.valueOf((((Number) version.get(this.instance)).shortValue()));
          this.oldVersion = shortObjValue;

          version.set(this.instance, shortObjValue + 1);

          ManagedInstance.LOG.debug("Version upgraded instance: {0} - {1}", this, shortObjValue);

          break;

        case INT:
          final int intValue = (((Number) version.get(this.instance)).intValue());
          this.oldVersion = intValue;

          version.set(this.instance, intValue + 1);

          ManagedInstance.LOG.debug("Version upgraded instance: {0} - {1}", this, intValue);

          break;
        case INT_OBJECT:
          final Integer intObjValue =
              version.get(this.instance) == null
                  ? 0
                  : //
                  Integer.valueOf(((Number) version.get(this.instance)).intValue());
          this.oldVersion = intObjValue;

          version.set(this.instance, intObjValue + 1);

          ManagedInstance.LOG.debug("Version upgraded instance: {0} - {1}", this, intObjValue);

          break;
        case LONG:
          final long longValue = (((Number) version.get(this.instance)).longValue());
          this.oldVersion = longValue;

          version.set(this.instance, longValue + 1);

          ManagedInstance.LOG.debug("Version upgraded instance: {0} - {1}", this, longValue);

          break;
        case LONG_OBJECT:
          final Long longObjValue =
              version.get(this.instance) == null
                  ? 0l
                  : //
                  Long.valueOf((((Number) version.get(this.instance)).longValue()));
          this.oldVersion = longObjValue;

          version.set(this.instance, longObjValue + 1);

          ManagedInstance.LOG.debug("Version upgraded instance: {0} - {1}", this, longObjValue);

          break;

        case TIMESTAMP:
          final Timestamp value = new Timestamp(System.currentTimeMillis());
          this.oldVersion = version.get(this.instance);

          version.set(this.instance, value);

          ManagedInstance.LOG.debug("Version upgraded instance: {0} - {1}", this, value);
      }
    }

    if (commit) {
      final Object newVersion = version.get(this.instance);
      rootType.performVersionUpdate(connection, this, this.oldVersion, newVersion);

      ManagedInstance.LOG.debug(
          "Version committed instance: {0} - {1} -> {2}", this, this.oldVersion, newVersion);

      this.oldVersion = null;
    } else {
      this.changed();
    }
  }