经过两天修正,足够稳定,发布0204,希望作为LTS版本
大石头 编写于 2020-02-04 22:44:36
X
using System;
using System.Linq;
using NewLife.Reflection;
using XCode.Configuration;
using XCode.DataAccessLayer;

namespace XCode.Sync
{
    /// <summary>同步框架从方接口</summary>
    public interface ISyncSlave
    {
        #region 方法
        /// <summary>最后同步时间</summary>
        /// <returns></returns>
        DateTime LastSync { get; set; }

        /// <summary>获取所有新添加的数据</summary>
        /// <param name="start"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        ISyncSlaveEntity[] GetAllNew(Int32 start, Int32 max);

        /// <summary>获取所有删除的数据</summary>
        /// <param name="start"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        ISyncSlaveEntity[] GetAllDelete(Int32 start, Int32 max);

        /// <summary>获取所有未同步的旧数据</summary>
        /// <param name="now"></param>
        /// <param name="start"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        ISyncSlaveEntity[] GetAllOld(DateTime now, Int32 start, Int32 max);

        /// <summary>根据主键查找</summary>
        /// <param name="key"></param>
        /// <returns></returns>
        ISyncSlaveEntity FindByKey(Object key);

        /// <summary>创建一个空白实体</summary>
        /// <returns></returns>
        ISyncSlaveEntity Create();

        /// <summary>获取要同步的字段名</summary>
        /// <returns></returns>
        String[] GetNames();
        #endregion
    }

    /// <summary>同步框架从方实体接口,由从方实体类实现</summary>
    public interface ISyncSlaveEntity : IIndexAccessor
    {
        #region 属性
        /// <summary>唯一标识数据的键值</summary>
        Object Key { get; }

        /// <summary>最后修改时间。包括修改同步状态为假删除</summary>
        DateTime LastUpdate { get; set; }

        /// <summary>最后同步时间。包括向主方询问数据是否已删除</summary>
        DateTime LastSync { get; set; }

        ///// <summary>同步状态。默认0添加1删除2</summary>
        //Int32 SyncStatus { get; set; }
        #endregion

        #region 方法
        /// <summary>改变主键。本地新增加的数据,在提交到提供方后,可能主键会改变(如自增字段),需要更新本地主键为新主键</summary>
        /// <param name="key"></param>
        void ChangeKey(Object key);

        ///// <summary>保存</summary>
        ///// <returns></returns>
        //Int32 Save();

        /// <summary>插入</summary>
        /// <returns></returns>
        Int32 Insert();

        /// <summary>更新</summary>
        /// <returns></returns>
        Int32 Update();

        /// <summary>删除本地数据</summary>
        /// <returns></returns>
        Int32 Delete();
        #endregion
    }

    /// <summary>同步框架从方,实体类默认实现。要求实体类实现<see cref="ISyncSlaveEntity"/>接口</summary>
    public class SyncSlave : ISyncSlave
    {
        #region 属性
        private IEntityOperate _Factory;
        /// <summary>工厂</summary>
        public IEntityOperate Factory { get { return _Factory; } set { _Factory = value; } }

        /// <summary>主键名</summary>
        protected virtual String KeyName { get { return Factory.Unique.Name; } }

        private String _LastUpdateName = "LastUpdate";
        /// <summary>最后更新字段名</summary>
        public virtual String LastUpdateName { get { return _LastUpdateName; } set { _LastUpdateName = value; } }

        private String _LastSyncName = "LastSync";
        /// <summary>最后更新字段名</summary>
        public virtual String LastSyncName { get { return _LastSyncName; } set { _LastSyncName = value; } }

        /// <summary>最后更新字段名。先硬编码,不考虑可变</summary>
        protected virtual Field LastUpdateField { get { return Factory.Table.FindByName(LastUpdateName); } }

        /// <summary>最后同步字段名</summary>
        protected virtual Field LastSyncField { get { return Factory.Table.FindByName(LastSyncName); } }
        #endregion

        #region 最后同步
        private DateTime? _LastSync;
        /// <summary>最后同步时间</summary>
        public DateTime LastSync
        {
            get
            {
                if (_LastSync == null) _LastSync = GetLastSync();

                return _LastSync.Value;
            }
            set { _LastSync = value; }
        }

        /// <summary>获取最后同步时间</summary>
        /// <returns></returns>
        protected virtual DateTime GetLastSync()
        {
            var dal = DAL.Create(Factory.ConnName);
            // 有效同步时间升序,取一个,即为最小值
            var list = Factory.FindAll(LastSyncField > DateTime.MinValue, LastSyncField.Asc(), null, 0, 1);
            if (list == null || list.Count < 1) return DateTime.MinValue;

            return (DateTime)list[0][LastSyncField];
        }
        #endregion

        #region 方法
        /// <summary>获取所有新添加的数据</summary>
        /// <param name="start"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public virtual ISyncSlaveEntity[] GetAllNew(Int32 start, Int32 max)
        {
            var dal = DAL.Create(Factory.ConnName);
            return GetAll(LastSyncField <= DateTime.MinValue | LastSyncField == null, start, max);
        }

        /// <summary>获取所有删除的数据</summary>
        /// <param name="start"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public virtual ISyncSlaveEntity[] GetAllDelete(Int32 start, Int32 max)
        {
            var dal = DAL.Create(Factory.ConnName);
            return GetAll(LastUpdateField <= DateTime.MinValue | LastUpdateField == null, start, max);
        }

        /// <summary>获取所有未同步的旧数据</summary>
        /// <param name="now"></param>
        /// <param name="start"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public virtual ISyncSlaveEntity[] GetAllOld(DateTime now, Int32 start, Int32 max)
        {
            //var dal = DAL.Create(Facotry.ConnName);
            return GetAll(LastSyncField < now, start, max);
        }

        ISyncSlaveEntity[] GetAll(Expression where, Int32 start, Int32 max)
        {
            var list = Factory.FindAll(where, null, null, start, max);
            if (list == null || list.Count < 1) return null;

            var rs = new ISyncSlaveEntity[list.Count];
            for (var i = 0; i < list.Count; i++)
            {
                rs[i] = list[i] as ISyncSlaveEntity;
            }
            return rs;
        }

        /// <summary>根据主键查找</summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual ISyncSlaveEntity FindByKey(Object key) { return Factory.FindByKey(key) as ISyncSlaveEntity; }

        /// <summary>创建一个空白实体</summary>
        /// <returns></returns>
        public virtual ISyncSlaveEntity Create() { return Factory.Create() as ISyncSlaveEntity; }

        /// <summary>获取要同步的字段名</summary>
        /// <returns></returns>
        public virtual String[] GetNames() { return Factory.FieldNames.ToArray(); }
        #endregion
    }
}