/// <summary> /// 把整个聚合对象的 Id 设置完整。 /// </summary> /// <param name="oldEntity"></param> /// <param name="newEntity"></param> private static void MergeIdRecur(Entity oldEntity, Entity newEntity) { oldEntity.LoadProperty(Entity.IdProperty, newEntity.GetProperty(Entity.IdProperty)); foreach (var field in oldEntity.GetLoadedChildren()) { var listProperty = field.Property as IListProperty; if (listProperty != null) { var oldChildren = field.Value as EntityList; var newChildren = newEntity.GetLazyList(listProperty) as EntityList; //两个集合应该是一样的数据、顺序?如果后期出现 bug,则修改此处的逻辑为查找到对应项再修改。 for (int i = 0, c = oldChildren.Count; i < c; i++) { MergeIdRecur(oldChildren[i], newChildren[i]); } //同步组合父对象 Id oldChildren.SyncParentEntityId(oldEntity); //同步 TreePId if (oldChildren.SupportTree) { for (int i = 0, c = oldChildren.Count; i < c; i++) { var oldChild = oldChildren[i]; var newChild = newChildren[i]; oldChild.TreePId = newChild.TreePId; } } } } }
private static void CalculateCollectValue(Entity entity, IManagedProperty property, ManagedPropertyChangedEventArgs args) { var distance = Convert.ToDouble(args.NewValue) - Convert.ToDouble(args.OldValue); var oldValue = Convert.ToDouble(entity.GetProperty(property)); entity.SetProperty(property, oldValue + distance); }
/// <summary> /// 复制指定的属性值。 /// </summary> /// <param name="source">从这个对象拷贝</param> /// <param name="property">拷贝这个属性</param> /// <param name="options">The options.</param> private void CopyProperty(Entity source, IManagedProperty property, CloneOptions options) { var refIndicator = property as IRefEntityProperty; if (refIndicator != null) { bool copyEntity = refIndicator.ReferenceType == ReferenceType.Parent ? options.HasAction(CloneActions.ParentRefEntity) : options.HasAction(CloneActions.RefEntities); if (!copyEntity) { return; } } else { var value = source.GetProperty(property); if (options.Method == CloneValueMethod.LoadProperty) { this.LoadProperty(property, value); } else { this.SetProperty(property, value); } } }
/// <summary> /// 清除子对象集合 /// </summary> /// <param name="oldEntity">The old entity.</param> /// <param name="entityInfo">The entity information.</param> protected virtual void MakeSavedCore(Entity oldEntity, EntityMeta entityInfo) { foreach (var item in entityInfo.ChildrenProperties) { var mp = item.ManagedProperty as IListProperty; //如果是懒加载属性,并且没有加载数据时,不需要遍历此属性值 if (!oldEntity.FieldExists(mp)) { continue; } var children = oldEntity.GetProperty(mp) as EntityList; if (children == null) { continue; } //清除已删除数据 children.CastTo <EntityList>().DeletedList.Clear(); //所有子对象,都标记为已保存 for (int i = children.Count - 1; i >= 0; i--) { var child = children[i] as Entity; if (child.IsDirty || child.IsNew) { MakeSaved(child); } } } oldEntity.MarkSaved(); }
/// <summary> /// 删除不必要的对象,只留下需要保存的“脏”数据 /// </summary> /// <param name="diffEntity">The difference entity.</param> /// <param name="entityInfo">The entity information.</param> protected virtual void ClearDataCore(Entity diffEntity, EntityMeta entityInfo) { foreach (var item in entityInfo.ChildrenProperties) { var mp = item.ManagedProperty; //如果是懒加载属性,并且没有加载数据时,不需要遍历此属性值 if (!diffEntity.FieldExists(mp)) { continue; } var children = diffEntity.GetProperty(mp) as EntityList; if (children == null) { continue; } for (int i = children.Count - 1; i >= 0; i--) { var child = children[i]; if (!child.IsDirty) { children.Remove(child); children.DeletedList.Remove(child); } else { this.ClearData(child); } } } }
/// <summary> /// 根据冗余路径从当前对象开始搜索,获取真实的属性值。 /// </summary> /// <param name="path"></param> /// <param name="from"> /// 本对象在路径中拥有的引用属性。 /// 在 D->C->B->A.Name 场景中,当前对象(this)可能是 C,那么 from 就是 C.BRefProperty. /// 如果没有指定此属性,则表示从第一个开始。 /// </param> /// <returns></returns> internal object GetRedundancyValue(RedundantPath path, IRefIdProperty from = null) { Entity refEntity = this; foreach (var refP in path.RefPathes) { if (from != null && refP.Property != from) { continue; } refEntity = refEntity.GetRefEntity((refP.Property as IRefProperty).RefEntityProperty); if (refEntity == null) { break; } } object value = null; if (refEntity != this && refEntity != null) { value = refEntity.GetProperty(path.ValueProperty.Property); } return(value); }
/// <summary> /// 复制指定的属性值。 /// </summary> /// <param name="source">从这个对象拷贝</param> /// <param name="property">拷贝这个属性</param> /// <param name="options">The options.</param> protected virtual void CopyProperty(Entity source, IManagedProperty property, CloneOptions options) { var value = source.GetProperty(property); if (options.Method == CloneValueMethod.LoadProperty) { this.LoadProperty(property, value); } else { this.SetProperty(property, value); } }
public bool MoveNext() { while (true) { _index++; if (_index >= _childProperties.Count) { break; } var property = _childProperties[_index]; var value = _entity.GetProperty(property) as IDomainComponent; if (value != null) { _current = new ChildPropertyField(property, value); return(true); } } return(false); }
/// <summary> /// 尝试更新依赖指定实体的值的冗余属性的值。 /// </summary> /// <param name="entity">变更了值属性的实体。依赖该实体的所有冗余属性都需要被更新。</param> /// <param name="repository">实体对应的仓库。</param> public void UpdateRedundancies(Entity entity, IRepository repository) { if (repository == null) { repository = entity.GetRepository(); } //如果有一些在冗余属性路径中的属性的值改变了,则开始更新数据库的中的所有冗余字段的值。 Entity dbEntity = null; var propertiesInPath = repository.GetPropertiesInRedundancyPath(); for (int i = 0, c = propertiesInPath.Count; i < c; i++) { var property = propertiesInPath[i]; //如果只有一个属性,那么就是它变更引起的更新 //否则,需要从数据库获取原始值来对比检测具体哪些属性值变更,然后再发起冗余更新。 bool isChanged = c == 1; var refProperty = property as IRefIdProperty; if (refProperty != null) { if (!isChanged) { if (dbEntity == null) { dbEntity = ForceGetById(entity, repository); } var dbId = dbEntity.GetRefId(refProperty); var newId = entity.GetRefId(refProperty); isChanged = !object.Equals(dbId, newId); } if (isChanged) { foreach (var path in property.InRedundantPathes) { //如果这条路径中是直接把引用属性的值作为值属性进行冗余,那么同样要进行值属性更新操作。 if (path.ValueProperty.Property == property) { this.UpdateRedundancyByRefValue(entity, path, refProperty); } //如果是引用变更了,并且只有一个 RefPath,则不需要处理。 //因为这个已经在属性刚变更时的处理函数中实时处理过了。 else if (path.RefPathes.Count > 1) { this.UpdateRedundancyByIntermidateRef(entity, path, refProperty); } } } } else { var newValue = entity.GetProperty(property); if (!isChanged) { if (dbEntity == null) { dbEntity = ForceGetById(entity, repository); } var dbValue = dbEntity.GetProperty(property); isChanged = !object.Equals(dbValue, newValue); } if (isChanged) { foreach (var path in property.InRedundantPathes) { UpdateRedundancyByValue(entity, path, newValue); } } } } entity.UpdateRedundancies = false; }
/// <summary> /// 冗余路径中非首位的引用属的值作为值属性进行冗余,那么同样要进行值属性更新操作。 /// </summary> /// <param name="entity">The entity.</param> /// <param name="path">The path.</param> /// <param name="refChanged">该引用属性值变化了</param> private void UpdateRedundancyByRefValue(Entity entity, RedundantPath path, IRefIdProperty refChanged) { var newValue = entity.GetProperty(refChanged); this.UpdateRedundancy(entity, path.Redundancy, newValue, path.RefPathes, entity.Id); }
/// <summary> /// 获取当前实体是否为一个‘幽灵’(即已经删除不再使用的数据)。 /// </summary> /// <param name="me"></param> /// <returns></returns> public static bool GetIsPhantom(Entity me) { return(me.GetProperty(IsPhantomProperty)); }
/// <summary> /// 复制目标对象的所有字段。 /// 子类重写此方法额外做以下几件事: /// 1. 如果有自定义字段,请在此方法中进行值拷贝。 /// 2. 如果有延迟加载的外键引用对象 ILazyEntityRef,请调用它的 Clone 方法进行拷贝。 /// 3. 如果使用了快速字段 FastField 来进行属性的缓存,请在基类完成 Clone 后,调用本类的 ResetFastField 方法来清空缓存。 /// </summary> /// <param name="source">The source.</param> /// <param name="options">The options.</param> /// <exception cref="System.ArgumentNullException">source /// or /// options</exception> protected virtual void CloneCore(Entity source, CloneOptions options) { if (source == null) { throw new ArgumentNullException("source"); } if (options == null) { throw new ArgumentNullException("options"); } var grabChildren = options.HasAction(CloneActions.GrabChildren); var childrenRecur = options.HasAction(CloneActions.ChildrenRecur); var copyId = options.HasAction(CloneActions.IdProperty); var ingoreList = options.RetrieveIgnoreListOnce(); //如果需要拷贝id,则应该先拷贝id,并立刻清空id的缓存。 //注意: //由于 IdProperty 在 AllProperties 中的位置并不是第一个。所以会出现拷贝其它属性时,再次访问本ID导致缓存重建。 //所以这里需要单独对 Id 进行一次拷贝。 if (copyId) { this.CopyProperty(source, IdProperty, options); } //复制目标对象的所有托管属性。 var allProperties = this.PropertiesContainer.GetAvailableProperties(); for (int i = 0, c = allProperties.Count; i < c; i++) { var property = allProperties[i]; if (property.IsReadOnly) { continue; } //var propertyMeta = property.GetMeta(this) as IPropertyMetadata; //过滤一些不需要拷贝的属性 if (property == IdProperty && !copyId) { continue; } if (ingoreList != null && ingoreList.Contains(property)) { continue; } //已经更改了GetLazyChildren方法,不再考虑null值的拷贝。 ////如果目标不存在这个值时,不需要也不能进行拷贝,否则会为懒加载属性的加载null值。 //if (!target.FieldManager.FieldExists(propertyInfo)) continue; if (property is IListProperty) { var listProperty = property as IListProperty; if (childrenRecur) { var sourceList = source.GetLazyList(listProperty); var targetList = this.GetLazyList(listProperty); targetList.Clone(sourceList, options); var isComposition = targetList.HasManyType == HasManyType.Composition; if (isComposition) { targetList.SetParentEntity(this); } } else if (grabChildren) { var children = source.GetProperty(property) as EntityList; this.LoadProperty(property, children); if (children == null) { return; } var isComposition = children.HasManyType == HasManyType.Composition; if (isComposition) { children.SetParentEntity(this); } } } else { this.CopyProperty(source, property, options); } } options.NotifyCloned(source, this); if (this.SupportTree) { this.OnTreeItemCloned(source, options); } }
/// <summary> /// 复制目标对象的所有字段。 /// 子类重写此方法额外做以下几件事: /// 1. 如果有自定义字段,请在此方法中进行值拷贝。 /// 2. 如果有延迟加载的外键引用对象 ILazyEntityRef,请调用它的 Clone 方法进行拷贝。 /// 3. 如果使用了快速字段 FastField 来进行属性的缓存,请在基类完成 Clone 后,调用本类的 ResetFastField 方法来清空缓存。 /// </summary> /// <param name="source">The source.</param> /// <param name="options">The options.</param> /// <exception cref="System.ArgumentNullException">source /// or /// options</exception> protected virtual void CloneCore(Entity source, CloneOptions options) { if (source == null) { throw new ArgumentNullException("source"); } if (options == null) { throw new ArgumentNullException("options"); } //准备一些控制变量 var grabChildren = options.HasAction(CloneActions.GrabChildren); var childrenRecur = options.HasAction(CloneActions.ChildrenRecur); var copyId = options.HasAction(CloneActions.IdProperty); var cloneParentRef = options.HasAction(CloneActions.ParentRefEntity); var cloneRef = options.HasAction(CloneActions.RefEntities); var ingoreList = options.RetrieveIgnoreList(false); //如果需要拷贝id,则应该先拷贝id。否则后续在拷贝组合子时,可能访问不当前实体的 Id。 if (copyId) { this.CopyProperty(source, IdProperty, options); } //复制目标对象的所有托管属性。 var allProperties = this.PropertiesContainer.GetAvailableProperties(); for (int i = 0, c = allProperties.Count; i < c; i++) { var property = allProperties[i]; if (property.IsReadOnly) { continue; } //过滤一些不需要拷贝的属性 if (property == IdProperty) { continue; //Id 已经提前处理过了。 } if (ingoreList != null && ingoreList.Contains(property)) { continue; } if (property is IListProperty) { if (childrenRecur || grabChildren) { if (!source.FieldExists(property)) { this.ResetProperty(property); } else { var listProperty = property as IListProperty; var sourceList = source.GetProperty(listProperty) as EntityList; EntityList children = null; if (childrenRecur) { children = this.LoadLazyList(listProperty, true); children.Clone(sourceList, options);//内部 Add 时会调用 children.SetParentEntity(this); } else//grabChildren { children = sourceList; this.LoadProperty(property, children);//Load 时会调用 children.SetParentEntity(this); } } } } else if (property is IRefEntityProperty) { bool copyEntity = (property as IRefEntityProperty).ReferenceType == ReferenceType.Parent ? cloneParentRef : cloneRef; if (copyEntity && source.GetProperty(property) != null) { this.CopyProperty(source, property, options); } } else { this.CopyProperty(source, property, options); } } var supportTree = this.SupportTree; if (supportTree) { this.CloneTreeRelations(source, options, childrenRecur, grabChildren, cloneParentRef); } //如果 Id 值没有拷贝,那么组合子实体中的 PId 需要重新整理。 //由于这种场景下没有拷贝 Id,又需要重新整理 PId 和 TreePId,所以可以使用 SetProperty 方法来变更实体的状态。 if (!copyId && (childrenRecur || grabChildren)) { foreach (var child in this.GetLoadedChildren()) { var list = child.Value as EntityList; if (list != null) { list.SetParentEntity(this); } } if (supportTree) { (this as ITreeComponent).EachNode(e => { e.SyncTreeChildrenPId(); return(false); }); } } //如果是新构建的实体,持久化状态也完全拷贝。(如果 Id 没有被拷贝,说明是只拷贝值,那么不需要变更新实体的状态) if (this.IsNew && copyId && !source.IsNew) { this.PersistenceStatus = source.PersistenceStatus; } options.NotifyCloned(source, this); }