forked from p81075629/datagear
解决编辑集合属性值元素时,元素的引用属性值无法保存的问题,原因:后台处理参数转换时,没有延迟处理循环引用
This commit is contained in:
parent
9085fd981b
commit
7532ef0426
|
@ -4,11 +4,15 @@
|
|||
|
||||
package org.datagear.persistence.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.datagear.model.Model;
|
||||
import org.datagear.model.Property;
|
||||
import org.datagear.model.support.MU;
|
||||
import org.datagear.model.support.PropertyModel;
|
||||
import org.datagear.persistence.features.KeyRule;
|
||||
import org.datagear.persistence.features.KeyRule.RuleType;
|
||||
import org.datagear.persistence.features.MappedBy;
|
||||
import org.datagear.persistence.mapper.Mapper;
|
||||
import org.datagear.persistence.mapper.MapperUtil;
|
||||
import org.datagear.persistence.mapper.ModelTableMapper;
|
||||
|
@ -83,4 +87,77 @@ public class PMU
|
|||
{
|
||||
return !isPrivate(model, property, propertyConcreteModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置属性值。
|
||||
* <p>
|
||||
* 此方法会处理{@linkplain MappedBy}双向关联,反向赋值。
|
||||
* </p>
|
||||
* <p>
|
||||
* 注意:此方法不会处理反向集合属性,因为此时obj仅是反向集合中的单个元素
|
||||
* </p>
|
||||
*
|
||||
* @param model
|
||||
* @param property
|
||||
* @param propertyModel
|
||||
* @param obj
|
||||
* @param propertyValue
|
||||
*/
|
||||
public static void setPropertyValue(Model model, Property property, PropertyModel propertyModel, Object obj,
|
||||
Object propertyValue)
|
||||
{
|
||||
Model pmodel = propertyModel.getModel();
|
||||
|
||||
if (propertyValue == null)
|
||||
{
|
||||
if (pmodel.getType().isPrimitive())
|
||||
;
|
||||
else
|
||||
property.set(obj, null);
|
||||
}
|
||||
else if (MU.isPrimitiveModel(pmodel))
|
||||
{
|
||||
property.set(obj, propertyValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
property.set(obj, propertyValue);
|
||||
|
||||
RelationMapper relationMapper = property.getFeature(RelationMapper.class);
|
||||
Mapper mapper = relationMapper.getMappers()[propertyModel.getIndex()];
|
||||
|
||||
String mappedTarget = null;
|
||||
if (mapper.isMappedBySource())
|
||||
mappedTarget = mapper.getMappedByTarget();
|
||||
else if (mapper.isMappedByTarget())
|
||||
mappedTarget = mapper.getMappedBySource();
|
||||
|
||||
// 反向设置属性值
|
||||
if (mappedTarget != null)
|
||||
{
|
||||
Property mappedProperty = MU.getProperty(pmodel, mappedTarget);
|
||||
|
||||
// 不处理反向集合属性,因为此时obj仅是反向集合中的单个元素
|
||||
if (MU.isMultipleProperty(mappedProperty))
|
||||
;
|
||||
else if (property.isCollection())
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Object> collection = (Collection<Object>) propertyValue;
|
||||
|
||||
for (Object ele : collection)
|
||||
mappedProperty.set(ele, obj);
|
||||
}
|
||||
else if (property.isArray())
|
||||
{
|
||||
Object[] array = (Object[]) propertyValue;
|
||||
|
||||
for (Object ele : array)
|
||||
mappedProperty.set(ele, obj);
|
||||
}
|
||||
else
|
||||
mappedProperty.set(propertyValue, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten
|
|||
else
|
||||
{
|
||||
UpdateInfoForAutoKeyUpdateRule updateInfo = new UpdateInfoForAutoKeyUpdateRule(property, i,
|
||||
pmm, myMapperIndex, updatePropertyValueElement);
|
||||
pmm, myMapperIndex, originalPropertyValueElement, updatePropertyValueElement);
|
||||
updateInfoForAutoKeyUpdateRules.add(updateInfo);
|
||||
}
|
||||
}
|
||||
|
@ -341,7 +341,8 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten
|
|||
else
|
||||
{
|
||||
UpdateInfoForAutoKeyUpdateRule updateInfo = new UpdateInfoForAutoKeyUpdateRule(property, i,
|
||||
pmm, myOriginalMapperIndex, updatePropertyValueElement);
|
||||
pmm, myOriginalMapperIndex, originalPropertyValueElement,
|
||||
updatePropertyValueElement);
|
||||
updateInfoForAutoKeyUpdateRules.add(updateInfo);
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +386,7 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten
|
|||
else
|
||||
{
|
||||
UpdateInfoForAutoKeyUpdateRule updateInfo = new UpdateInfoForAutoKeyUpdateRule(property, i,
|
||||
pmm, j, updatePropertyValue);
|
||||
pmm, j, originalPropertyValue, updatePropertyValue);
|
||||
updateInfoForAutoKeyUpdateRules.add(updateInfo);
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +418,7 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten
|
|||
|
||||
int myCount = updatePropertyTableData(cn, dialect, table, model, updateCondition,
|
||||
updateInfo.getProperty(), updateInfo.getPropertyModelMapper(), null,
|
||||
originalPropertyValues[updateInfo.getPropertyIndex()], updatePropertyValue, null, false,
|
||||
updateInfo.getOriginalPropertyValue(), updatePropertyValue, null, false,
|
||||
expressionEvaluationContext);
|
||||
|
||||
if (myCount == 0)
|
||||
|
@ -968,6 +969,8 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten
|
|||
|
||||
private int propertyModelMapperIndex;
|
||||
|
||||
private Object originalPropertyValue;
|
||||
|
||||
private Object updatePropertyValue;
|
||||
|
||||
public UpdateInfoForAutoKeyUpdateRule()
|
||||
|
@ -976,13 +979,15 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten
|
|||
}
|
||||
|
||||
public UpdateInfoForAutoKeyUpdateRule(Property property, int propertyIndex,
|
||||
PropertyModelMapper<?> propertyModelMapper, int propertyModelMapperIndex, Object updatePropertyValue)
|
||||
PropertyModelMapper<?> propertyModelMapper, int propertyModelMapperIndex, Object originalPropertyValue,
|
||||
Object updatePropertyValue)
|
||||
{
|
||||
super();
|
||||
this.property = property;
|
||||
this.propertyIndex = propertyIndex;
|
||||
this.propertyModelMapper = propertyModelMapper;
|
||||
this.propertyModelMapperIndex = propertyModelMapperIndex;
|
||||
this.originalPropertyValue = originalPropertyValue;
|
||||
this.updatePropertyValue = updatePropertyValue;
|
||||
}
|
||||
|
||||
|
@ -1026,6 +1031,16 @@ public class UpdatePersistenceOperation extends AbstractExpressionModelPersisten
|
|||
this.propertyModelMapperIndex = propertyModelMapperIndex;
|
||||
}
|
||||
|
||||
public Object getOriginalPropertyValue()
|
||||
{
|
||||
return originalPropertyValue;
|
||||
}
|
||||
|
||||
public void setOriginalPropertyValue(Object originalPropertyValue)
|
||||
{
|
||||
this.originalPropertyValue = originalPropertyValue;
|
||||
}
|
||||
|
||||
public Object getUpdatePropertyValue()
|
||||
{
|
||||
return updatePropertyValue;
|
||||
|
|
|
@ -293,11 +293,11 @@ public abstract class AbstractDataConverter
|
|||
/**
|
||||
* 将{@linkplain #REF_NAME}的值解析为引用目标对象。
|
||||
*
|
||||
* @param ref
|
||||
* @param refContext
|
||||
* @param ref
|
||||
* @return
|
||||
*/
|
||||
protected Object resolveRefTarget(String ref, RefContext refContext)
|
||||
protected Object resolveRefTarget(RefContext refContext, String ref)
|
||||
{
|
||||
if (REF_VALUE_ROOT.equals(ref))
|
||||
return refContext.getRoot();
|
||||
|
@ -603,6 +603,8 @@ public abstract class AbstractDataConverter
|
|||
|
||||
private Map<String, Object> pathObjects = new HashMap<String, Object>();
|
||||
|
||||
private Map<String, String> lazyRefs = new HashMap<String, String>();
|
||||
|
||||
public RefContext()
|
||||
{
|
||||
super();
|
||||
|
@ -650,5 +652,20 @@ public abstract class AbstractDataConverter
|
|||
if (REF_VALUE_ROOT.equals(path))
|
||||
this.root = object;
|
||||
}
|
||||
|
||||
public boolean hasLazyRefs()
|
||||
{
|
||||
return (this.lazyRefs != null && !this.lazyRefs.isEmpty());
|
||||
}
|
||||
|
||||
public Map<String, String> getLazyRefs()
|
||||
{
|
||||
return lazyRefs;
|
||||
}
|
||||
|
||||
public void addLazyRefs(String path, String refValue)
|
||||
{
|
||||
this.lazyRefs.put(path, refValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,13 @@ public class ClassDataConverter extends AbstractDataConverter
|
|||
*/
|
||||
public <T> T convert(Object obj, Class<T> type) throws ConverterException
|
||||
{
|
||||
return convertObj(null, obj, type, new RefContext());
|
||||
RefContext refContext = new RefContext();
|
||||
|
||||
T target = convertObj(null, obj, type, refContext);
|
||||
|
||||
handleLazyRefs(target, refContext);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +64,13 @@ public class ClassDataConverter extends AbstractDataConverter
|
|||
*/
|
||||
public <T> T[] convertToArray(Object obj, Class<T> type) throws ConverterException
|
||||
{
|
||||
return convertObjToArray(null, obj, type, new RefContext());
|
||||
RefContext refContext = new RefContext();
|
||||
|
||||
T[] target = convertObjToArray(null, obj, type, refContext);
|
||||
|
||||
handleLazyRefs(target, refContext);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,7 +85,13 @@ public class ClassDataConverter extends AbstractDataConverter
|
|||
public <T> Collection<T> convertToCollection(Object obj, Class<T> type, Class<? extends Collection> collectionType)
|
||||
throws ConverterException
|
||||
{
|
||||
return convertObjToCollection(null, obj, type, collectionType, new RefContext());
|
||||
RefContext refContext = new RefContext();
|
||||
|
||||
Collection<T> target = convertObjToCollection(null, obj, type, collectionType, refContext);
|
||||
|
||||
handleLazyRefs(target, refContext);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,9 +155,18 @@ public class ClassDataConverter extends AbstractDataConverter
|
|||
|
||||
if (isRefMap(map))
|
||||
{
|
||||
String ref = getRefValue(map);
|
||||
String refValue = getRefValue(map);
|
||||
Object refTarget = resolveRefTarget(refContext, refValue);
|
||||
|
||||
return (T) resolveRefTarget(ref, refContext);
|
||||
// 引用有可能在目标未被解析前先被处理,此时需要延迟处理
|
||||
if (refTarget != null)
|
||||
return (T) refTarget;
|
||||
else
|
||||
{
|
||||
refContext.addLazyRefs(namePath, refValue);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
T re = createInstance(type);
|
||||
|
@ -513,6 +540,121 @@ public class ClassDataConverter extends AbstractDataConverter
|
|||
return re;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理延迟引用。
|
||||
*
|
||||
* @param obj
|
||||
* @param refContext
|
||||
*/
|
||||
protected void handleLazyRefs(Object obj, RefContext refContext)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
|
||||
if (!refContext.hasLazyRefs())
|
||||
return;
|
||||
|
||||
Map<String, String> lazyRefs = refContext.getLazyRefs();
|
||||
|
||||
for (Map.Entry<String, String> entry : lazyRefs.entrySet())
|
||||
{
|
||||
String refValue = entry.getValue();
|
||||
|
||||
Object target = resolveRefTarget(refContext, refValue);
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
PropertyPath propertyPath = PropertyPath.valueOf(entry.getKey());
|
||||
|
||||
setValue(obj, propertyPath, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对象属性值。
|
||||
*
|
||||
* @param obj
|
||||
* @param propertyPath
|
||||
* @param value
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setValue(Object obj, PropertyPath propertyPath, Object value)
|
||||
{
|
||||
Object owner = obj;
|
||||
|
||||
for (int i = 0, len = propertyPath.length(); i < len; i++)
|
||||
{
|
||||
if (owner == null)
|
||||
throw new ConverterException("The owner object of index [" + i + "] must not be null");
|
||||
|
||||
if (i == len - 1)
|
||||
{
|
||||
if (owner instanceof Map<?, ?>)
|
||||
{
|
||||
if (!propertyPath.isProperty(i))
|
||||
throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]");
|
||||
|
||||
((Map<String, Object>) owner).put(propertyPath.getPropertyName(i), value);
|
||||
}
|
||||
else if (owner instanceof Object[])
|
||||
{
|
||||
if (!propertyPath.isElement(i))
|
||||
throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]");
|
||||
|
||||
((Object[]) owner)[propertyPath.getElementIndex(i)] = value;
|
||||
}
|
||||
else if (owner instanceof List<?>)
|
||||
{
|
||||
if (!propertyPath.isElement(i))
|
||||
throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]");
|
||||
|
||||
((List<Object>) owner).set(propertyPath.getElementIndex(i), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!propertyPath.isProperty(i))
|
||||
throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]");
|
||||
|
||||
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(owner);
|
||||
beanWrapper.setPropertyValue(propertyPath.getPropertyName(i), value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (owner instanceof Map<?, ?>)
|
||||
{
|
||||
if (!propertyPath.isProperty(i))
|
||||
throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]");
|
||||
|
||||
owner = ((Map<String, Object>) owner).get(propertyPath.getPropertyName(i));
|
||||
}
|
||||
else if (owner instanceof Object[])
|
||||
{
|
||||
if (!propertyPath.isElement(i))
|
||||
throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]");
|
||||
|
||||
owner = ((Object[]) owner)[propertyPath.getElementIndex(i)];
|
||||
}
|
||||
else if (owner instanceof List<?>)
|
||||
{
|
||||
if (!propertyPath.isElement(i))
|
||||
throw new ConverterException("The " + i + "-th must be element of [" + propertyPath + "]");
|
||||
|
||||
owner = ((List<Object>) owner).get(propertyPath.getElementIndex(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!propertyPath.isProperty(i))
|
||||
throw new ConverterException("The " + i + "-th must be property of [" + propertyPath + "]");
|
||||
|
||||
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(owner);
|
||||
owner = beanWrapper.getPropertyValue(propertyPath.getPropertyName(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属性类型信息。
|
||||
* <p>
|
||||
|
|
|
@ -17,9 +17,9 @@ import org.datagear.model.support.DefaultDynamicBean;
|
|||
import org.datagear.model.support.MU;
|
||||
import org.datagear.model.support.PropertyModel;
|
||||
import org.datagear.model.support.PropertyPath;
|
||||
import org.datagear.model.support.PropertyPathInfo;
|
||||
import org.datagear.persistence.collection.SizeOnlyCollection;
|
||||
import org.datagear.persistence.mapper.Mapper;
|
||||
import org.datagear.persistence.mapper.RelationMapper;
|
||||
import org.datagear.persistence.support.PMU;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
|
@ -50,7 +50,13 @@ public class ModelDataConverter extends AbstractDataConverter
|
|||
*/
|
||||
public Object convert(Object obj, Model model) throws ConverterException
|
||||
{
|
||||
return convertObj(null, obj, model, new RefContext());
|
||||
RefContext refContext = new RefContext();
|
||||
|
||||
Object target = convertObj(null, obj, model, refContext);
|
||||
|
||||
handleLazyRefs(model, target, refContext);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +69,13 @@ public class ModelDataConverter extends AbstractDataConverter
|
|||
*/
|
||||
public Object[] convertToArray(Object obj, Model model) throws ConverterException
|
||||
{
|
||||
return convertObjToArray(null, obj, model, new RefContext());
|
||||
RefContext refContext = new RefContext();
|
||||
|
||||
Object[] target = convertObjToArray(null, obj, model, refContext);
|
||||
|
||||
handleLazyRefs(model, target, refContext);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +90,46 @@ public class ModelDataConverter extends AbstractDataConverter
|
|||
public Collection<Object> convertToCollection(Object obj, Model model, Class<? extends Collection> collectionType)
|
||||
throws ConverterException
|
||||
{
|
||||
return convertObjToCollection(null, obj, model, collectionType, new RefContext());
|
||||
RefContext refContext = new RefContext();
|
||||
|
||||
Collection<Object> target = convertObjToCollection(null, obj, model, collectionType, refContext);
|
||||
|
||||
handleLazyRefs(model, target, refContext);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理延迟引用。
|
||||
*
|
||||
* @param model
|
||||
* @param obj
|
||||
* @param refContext
|
||||
*/
|
||||
protected void handleLazyRefs(Model model, Object obj, RefContext refContext)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
|
||||
if (!refContext.hasLazyRefs())
|
||||
return;
|
||||
|
||||
Map<String, String> lazyRefs = refContext.getLazyRefs();
|
||||
|
||||
for (Map.Entry<String, String> entry : lazyRefs.entrySet())
|
||||
{
|
||||
String refValue = entry.getValue();
|
||||
|
||||
Object target = resolveRefTarget(refContext, refValue);
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
PropertyPathInfo propertyPathInfo = PropertyPathInfo.valueOf(model,
|
||||
PropertyPath.valueOf(entry.getKey()), obj);
|
||||
|
||||
propertyPathInfo.setValueTail(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,8 +188,18 @@ public class ModelDataConverter extends AbstractDataConverter
|
|||
|
||||
if (isRefMap(map))
|
||||
{
|
||||
String ref = getRefValue(map);
|
||||
return resolveRefTarget(ref, refContext);
|
||||
String refValue = getRefValue(map);
|
||||
Object refTarget = resolveRefTarget(refContext, refValue);
|
||||
|
||||
// 引用有可能在目标未被解析前先被处理,此时需要延迟处理
|
||||
if (refTarget != null)
|
||||
return refTarget;
|
||||
else
|
||||
{
|
||||
refContext.addLazyRefs(namePath, refValue);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Object re = model.newInstance();
|
||||
|
@ -191,7 +252,7 @@ public class ModelDataConverter extends AbstractDataConverter
|
|||
value = convertObj(myFullPropertyPath, rawValue, pmodel, refContext);
|
||||
}
|
||||
|
||||
setPropertyValue(pmodel, property, propertyModel, re, value);
|
||||
setPropertyValue(model, property, propertyModel, re, value);
|
||||
}
|
||||
|
||||
return re;
|
||||
|
@ -579,55 +640,6 @@ public class ModelDataConverter extends AbstractDataConverter
|
|||
protected void setPropertyValue(Model model, Property property, PropertyModel propertyModel, Object obj,
|
||||
Object propertyValue)
|
||||
{
|
||||
Model pmodel = propertyModel.getModel();
|
||||
|
||||
if (propertyValue == null)
|
||||
{
|
||||
if (pmodel.getType().isPrimitive())
|
||||
;
|
||||
else
|
||||
property.set(obj, null);
|
||||
}
|
||||
else if (MU.isPrimitiveModel(pmodel))
|
||||
{
|
||||
property.set(obj, propertyValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
property.set(obj, propertyValue);
|
||||
|
||||
RelationMapper relationMapper = property.getFeature(RelationMapper.class);
|
||||
Mapper mapper = relationMapper.getMappers()[propertyModel.getIndex()];
|
||||
|
||||
String mappedTarget = null;
|
||||
if (mapper.isMappedBySource())
|
||||
mappedTarget = mapper.getMappedByTarget();
|
||||
else if (mapper.isMappedByTarget())
|
||||
mappedTarget = mapper.getMappedBySource();
|
||||
|
||||
// 反向设置属性值
|
||||
if (mappedTarget != null)
|
||||
{
|
||||
Property mappedProperty = MU.getProperty(pmodel, mappedTarget);
|
||||
|
||||
if (property.isCollection())
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Object> collection = (Collection<Object>) propertyValue;
|
||||
|
||||
for (Object ele : collection)
|
||||
mappedProperty.set(ele, obj);
|
||||
}
|
||||
else if (property.isArray())
|
||||
{
|
||||
Object[] array = (Object[]) propertyValue;
|
||||
|
||||
for (Object ele : array)
|
||||
mappedProperty.set(ele, obj);
|
||||
}
|
||||
else
|
||||
mappedProperty.set(propertyValue, obj);
|
||||
}
|
||||
}
|
||||
PMU.setPropertyValue(model, property, propertyModel, obj, propertyValue);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue