Ejemplo n.º 1
0
        /// <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;
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        /// <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);
                }
            }
        }
Ejemplo n.º 4
0
        /// <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();
        }
Ejemplo n.º 5
0
        /// <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);
                    }
                }
            }
        }
Ejemplo n.º 6
0
        /// <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);
        }
Ejemplo n.º 7
0
        /// <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);
            }
        }
Ejemplo n.º 8
0
            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);
            }
Ejemplo n.º 9
0
        /// <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;
        }
Ejemplo n.º 10
0
        /// <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);
        }
Ejemplo n.º 11
0
 /// <summary>
 /// 获取当前实体是否为一个‘幽灵’(即已经删除不再使用的数据)。
 /// </summary>
 /// <param name="me"></param>
 /// <returns></returns>
 public static bool GetIsPhantom(Entity me)
 {
     return(me.GetProperty(IsPhantomProperty));
 }
Ejemplo n.º 12
0
        /// <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);
            }
        }
Ejemplo n.º 13
0
        /// <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);
        }