/** 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); } }
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; }