public int bulkUpdateByPrimaryKey(
      final String entityName, final Map<String, ?> updateValues, final List<Long> keys) {
    int result = 0;

    if ((entityName == null)
        || (updateValues == null)
        || updateValues.isEmpty()
        || (keys == null)
        || keys.isEmpty()) {
      return 0;
    }

    try {
      final GenericHelper entityHelper = delegatorInterface.getEntityHelper(entityName);
      final ModelEntity modelEntity = delegatorInterface.getModelEntity(entityName);

      final List<String> pks = modelEntity.getPkFieldNames();
      if (pks.size() != 1) {
        throw new DataAccessException(
            "BulkUpdateByPrimaryKey only works for single column keys at this moment.");
      }
      final String pkName = pks.get(0);

      final Updater updater =
          new Updater(
              ModelFieldTypeReader.getModelFieldTypeReader(entityHelper.getHelperName()),
              entityName);
      final List<Updater.Value> params = new ArrayList<Updater.Value>();

      final StringBuilder updateSql = new StringBuilder("UPDATE ");

      updateSql.append(modelEntity.getTableName(entityHelper.getHelperName()));
      updateSql.append(" SET ");
      // generate the update sql
      for (final Iterator<String> iterator = updateValues.keySet().iterator();
          iterator.hasNext(); ) {
        final String column = iterator.next();
        updateSql.append(" ");
        final ModelField field = modelEntity.getField(column);
        updateSql.append(field.getColName());
        updateSql.append(" = ");
        params.add(updater.create(field, updateValues.get(column)));
        updateSql.append("? ");
        if (iterator.hasNext()) {
          updateSql.append(", ");
        }
      }

      // generate the where clause
      updateSql.append(" WHERE ");

      // batch the update
      final int batchSize = getQueryBatchSize();

      int currentIndex = 0;

      while (currentIndex < keys.size()) {
        int i = 0;
        final StringBuilder idClause = new StringBuilder();
        final ArrayList<Long> idParams = new ArrayList<Long>();
        for (final Iterator<Long> iterator = keys.subList(currentIndex, keys.size()).iterator();
            iterator.hasNext() && (i < batchSize);
            i++) {
          final Long key = iterator.next();
          idClause.append(" ");
          idClause.append(pkName);
          idClause.append(" = ");
          idParams.add(key);
          idClause.append("? ");

          if (iterator.hasNext() && ((i + 1) < batchSize)) {
            idClause.append(" or ");
          }
        }

        final SQLProcessor processor = new AutoCommitSQLProcessor(entityHelper.getHelperName());
        processor.prepareStatement(updateSql.toString() + idClause.toString());
        for (final Updater.Value param : params) {
          param.setValue(processor);
        }
        for (final Long idParam : idParams) {
          processor.setValue(idParam);
        }

        try {
          result = processor.executeUpdate();
        } finally {
          processor.close();
        }
        currentIndex += i;
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } catch (final SQLException e) {
      throw new DataAccessException(e);
    } catch (final NoClassDefFoundError e) {
      // under JDK 1.3 unit tests - javax.sql.XADataSource cannot be found.
      // this shouldn't affect runtime - application servers should ship the jar
    }
    return result;
  }