Exemplo n.º 1
0
 /** Update the object in the database. */
 public int update(DatabaseConnection databaseConnection, T data, ObjectCache objectCache)
     throws SQLException {
   try {
     // there is always and id field as an argument so just return 0 lines updated
     if (argFieldTypes.length <= 1) {
       return 0;
     }
     Object[] args = getFieldObjects(data);
     Object newVersion = null;
     if (versionFieldType != null) {
       newVersion = versionFieldType.extractJavaFieldValue(data);
       newVersion = versionFieldType.moveToNextValue(newVersion);
       args[versionFieldTypeIndex] = versionFieldType.convertJavaFieldToSqlArgValue(newVersion);
     }
     int rowC = databaseConnection.update(statement, args, argFieldTypes);
     if (rowC > 0) {
       if (newVersion != null) {
         // if we have updated a row then update the version field in our object to the new value
         versionFieldType.assignField(data, newVersion, false, null);
       }
       if (objectCache != null) {
         // if we've changed something then see if we need to update our cache
         Object id = idField.extractJavaFieldValue(data);
         T cachedData = objectCache.get(clazz, id);
         if (cachedData != null && cachedData != data) {
           // copy each field from the updated data into the cached object
           for (FieldType fieldType : tableInfo.getFieldTypes()) {
             if (fieldType != idField) {
               fieldType.assignField(
                   cachedData, fieldType.extractJavaFieldValue(data), false, objectCache);
             }
           }
         }
       }
     }
     logger.debug(
         "update data with statement '{}' and {} args, changed {} rows",
         statement,
         args.length,
         rowC);
     if (args.length > 0) {
       // need to do the (Object) cast to force args to be a single object
       logger.trace("update arguments: {}", (Object) args);
     }
     return rowC;
   } catch (SQLException e) {
     throw SqlExceptionUtil.create(
         "Unable to run update stmt on object " + data + ": " + statement, e);
   }
 }
Exemplo n.º 2
0
  public T mapRow(DatabaseResults results) throws SQLException {
    Map<String, Integer> colPosMap;
    if (columnPositions == null) {
      colPosMap = new HashMap<String, Integer>();
    } else {
      colPosMap = columnPositions;
    }

    ObjectCache objectCache = results.getObjectCache();
    Object id = null;
    if (objectCache != null) {
      id = idField.resultToJava(results, colPosMap);
      T cachedInstance = objectCache.get(entityConfig, id);
      if (cachedInstance != null) {
        // if we have a cached instance for this id then return it
        return cachedInstance;
      }
    }

    // create our instance
    List<PropertyConfig> instancePropertyConfigs = new ArrayList<>();
    T instance =
        createInstanceForResults(
            entityConfig, results, colPosMap, instancePropertyConfigs, resultsPropertyConfigs);

    if (objectCache != null && id != null) {
      // why not adding instance already here to cache? Avoids multiple retrievals on (deep)
      // recursive dependencies on its fields
      objectCache.put(
          (Class<T>) instance.getClass(),
          id,
          instance); // don't use clazz variable here as for tables with inheritance this might be
                     // wrong (it might only be the parent class)
    }

    // populate its fields
    Boolean foreignCollections = false;

    for (PropertyConfig propertyConfig : instancePropertyConfigs) {
      if (propertyConfig.isForeignCollection()) {
        foreignCollections = true;
      } else {
        Object val = propertyConfig.resultToJava(results, colPosMap);
        /*
         * This is pretty subtle. We introduced multiple foreign fields to the same type which use the {@link
         * ForeignCollectionField} foreignColumnName field. The bug that was created was that all the fields
         * were then set with the parent class. Only the fields that have a matching id value should be set to
         * the parent. We had to add the val.equals logic.
         */
        if (val != null
            && parent != null
            && propertyConfig.getType() == parent.getClass()
            && val.equals(parentId)) {
          propertyConfig.assignField(instance, parent, true, objectCache);
        } else {
          propertyConfig.assignField(instance, val, false, objectCache);
        }
        if (propertyConfig == idField) {
          id = val;
        }
      }
    }

    // if we have a cache and we have an id then add it to the cache
    //    if (objectCache != null && id != null) { // for ManyToMany collections it is of great
    // importance that instance will be cached already here, before ForeignCollections will be built
    //      objectCache.put(clazz, id, instance);
    //    }

    if (foreignCollections) {
      // go back and initialize any foreign collections
      for (PropertyConfig propertyConfig : instancePropertyConfigs) {
        if (propertyConfig.isForeignCollection()) {
          Collection collection =
              propertyConfig.buildForeignCollection(
                  instance, id); // cda: implement against interfaces, not implementations
          if (collection != null) {
            propertyConfig.assignField(instance, collection, false, objectCache);
          }
        }
      }
    }

    if (columnPositions == null) {
      columnPositions = colPosMap;
    }

    entityConfig.invokePostLoadLifeCycleMethod(instance);

    return instance;
  }