zoukankan      html  css  js  c++  java
  • WebForm —— 页面状态自动加载和保存(下)

    很久之前写完了上、中两篇,因为各种原因吧,到现在也没有完成下篇,心里一直有些愧疚。好了,废话不说了,把下篇补上,也是我用到现在的代码。

    第一步,新建一个类,并且让类从 BasePage 继承。

    第二步,重写 BasePage 类的两个虚方法:GetCacheData 和 SaveCacheData ,分别处理数据的 Load 和 Save 。

    第三步,保存这个类,并让页面的后台类(系统默认继承自 Page)继承自这个新类就可以了。

    好了,步骤理解之后,原理在上中两篇说的差不多了,剩下的看代码就行了,有问题给我留言就 OK 。

    首先是中篇中提到的的 AutoSaveAttribute 特性类:

    using System;
    using System.Diagnostics;
    
    namespace Lenic.Web
    {
        /// <summary>
        /// 自动保存属性,配合 BasePage 能够实现 Web 页面后台代码类字段或属性的自动保存和加载。
        /// </summary>
        [DebuggerStepThrough]
        [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
        public class AutoSaveAttribute : Attribute
        {
            /// <summary>
            /// 初始化创建一个 <see cref="AutoSaveAttribute"/> 类的实例,使得具有该属性的类的属性或字段具有自动保存的特性。
            /// </summary>
            public AutoSaveAttribute() { }
        }
    }

    然后是核心处理逻辑 BasePage 虚基类:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Reflection;
    using System.Web.UI;
    
    namespace Lenic.Web
    {
        /// <summary>
        /// 提供了 Web 页面自动保存属性处理的基类
        /// </summary>
        [DebuggerStepThrough]
        public abstract class BasePage : Page
        {
            #region Reload Fields And Properties
            /// <summary>
            /// 引发 <see cref="E:System.Web.UI.Control.Load"/> 事件。
            /// </summary>
            /// <param name="e">包含事件数据的 <see cref="T:System.EventArgs"/> 对象。</param>
            protected override void OnLoad(EventArgs e)
            {
                // 初始化当前用户控件的缓冲字典
                InitCacheDic();
    
                if (Page.IsPostBack)
                {
                    // 获得缓冲数据列表
                    var list = GetCacheData();
    
                    // 自动加载 AutoSave 属性保存的值
                    int index = 0;
                    foreach (MemberInfo info in CacheDic[CurrType])
                    {
                        if (info.MemberType == MemberTypes.Property)
                        {
                            PropertyInfo pi = info as PropertyInfo;
                            object value = list[index];
                            if (value != null)
                                pi.SetValue(this, value, null);
                        }
                        else if (info.MemberType == MemberTypes.Field)
                        {
                            FieldInfo fi = info as FieldInfo;
                            object value = list[index];
                            fi.SetValue(this, value);
                        }
                        index++;
                    }
                }
                base.OnLoad(e);
            }
            #endregion
    
            #region Save Fields And Properties
            /// <summary>
            /// 在这里实现属性的自动保存。
            /// </summary>
            protected override object SaveViewState()
            {
                // 初始化当前用户控件的缓冲字典
                InitCacheDic();
    
                // 初始化要保存的属性值列表
                List<object> list = new List<object>();
                foreach (MemberInfo info in CacheDic[CurrType])
                {
                    if (info.MemberType == MemberTypes.Property)
                    {
                        PropertyInfo pi = info as PropertyInfo;
                        list.Add(pi.GetValue(this, null));
                    }
                    else if (info.MemberType == MemberTypes.Field)
                    {
                        FieldInfo fi = info as FieldInfo;
                        list.Add(fi.GetValue(this));
                    }
                }
    
                // 保存更改
                SaveCacheData(list);
    
                return base.SaveViewState();
            }
            #endregion
    
            #region Business Properties
            /// <summary>
            /// 用户控件类型及自动保存属性成员缓冲字典
            /// </summary>
            protected static Dictionary<Type, MemberInfo[]> CacheDic = null;
    
            /// <summary>
            /// 当前页面的类型
            /// </summary>
            protected Type CurrType = null;
    
            /// <summary>
            /// 获得成员列表的绑定标识.
            /// </summary>
            private static readonly BindingFlags Flag;
    
            /// <summary>
            /// 初始化 <see cref="BasePage"/> 类.
            /// </summary>
            static BasePage()
            {
                CacheDic = new Dictionary<Type, MemberInfo[]>();
    
                Flag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.FlattenHierarchy;
            }
    
            /// <summary>
            /// 初始化当前页面的缓冲字典
            /// </summary>
            private void InitCacheDic()
            {
                // 获得当前实例类型
                CurrType = GetType();
    
                MemberInfo[] mems = null;
                if (!CacheDic.TryGetValue(CurrType, out mems))
                {
                    var list = CurrType.GetMembers(Flag)
                        .Where(p => Attribute.IsDefined(p, typeof(AutoSaveAttribute), false))
                        .ToArray();
                    CacheDic[CurrType] = list;
                }
            }
            #endregion
    
            #region Data Fetch
            /// <summary>
            /// 获得缓存的数据。
            /// </summary>
            /// <returns>重获的数据。</returns>
            protected abstract List<object> GetCacheData();
    
            /// <summary>
            /// 保存需要缓存的数据。
            /// </summary>
            /// <param name="data">需要保存的数据数组。</param>
            protected abstract void SaveCacheData(List<object> data);
            #endregion
        }
    }

    其次是对 GetCacheData 方法和 SaveCacheData 的实现:

    private ICacheList _currCache = null;
    private ICacheList CurrCache
    {
        get
        {
            if (_currCache == null)
            {
                _currCache = SqliteCacheList.NewInstance(CurrUser.SessionID, CurrUser.ID, CurrType.FullName);
                _currCache.LoadPageData();
            }
            return _currCache;
        }
    }
    
    protected override List<object> GetCacheData()
    {
        var data = CurrCache.Where(p => p.PageID == CurrType.FullName)
            .Select(p => p.Data == null ? null : p.Data.DeserializeFromByte<object>())
            .ToList();
    
        return data;
    }
    
    protected override void SaveCacheData(List<object> data)
    {
        data.ForEach((p, i) => CurrCache[i].Data = p == null ? null : p.SerializeToByte());
    
        CurrCache.Save();
    }

    这里用到了一些自定义的扩展方法:

    List<T> 类的 ForEach 方法添加了第二个参数 i 表示当前索引值。

    DeserializeFromByte<T> 是 byte[] 字节数组反序列化为 T 类型对象的扩展。

    SerializeToByte 是将当前对象序列化为 byte[] 字节数组的扩展。

    这三个方法应该问题都不大,百度一下就能找到类似的实现,这里就不再贴代码了。

    再次是缓存的具体实现代码。下面的代码是我个人实现的方法,每个人的想法可能都不同,权当抛砖引玉了:

    观察仔细的童鞋,可以看到 ICacheList 接口,这就是我自定义的一个接口:

    using System.Collections.Generic;
    
    namespace Lenic.Web.Caches
    {
        /// <summary>
        /// 缓存列表
        /// </summary>
        public interface ICacheList : IEnumerable<CacheItem>
        {
            /// <summary>
            /// 【自动新建】获得或设置缓存项。
            /// </summary>
            /// <param name="i">项的索引</param>
            /// <returns>缓存项</returns>
            CacheItem this[int i] { get; set; }
            /// <summary>
            /// 从数据库中加载数据
            /// </summary>
            /// <typeparam name="T">数据的类型</typeparam>
            /// <param name="dataId">数据标识</param>
            /// <returns>还原的原始数据</returns>
            T LoadData<T>(string dataId);
            /// <summary>
            /// 从数据库中加载页面数据
            /// </summary>
            /// <returns>加载后的列表</returns>
            ICacheList LoadPageData();
            /// <summary>
            /// 持久化数据变化
            /// </summary>
            void Save();
        }
    }

    其中 IEnumerable<CacheItem> 中的 CacheItem 表示缓存项的虚基类:

    using System;
    using System.Diagnostics;
    
    using Lenic.Data;
    using Lenic.Extensions;
    
    namespace Lenic.Web.Caches
    {
        /// <summary>
        /// 缓存项
        /// </summary>
        [Serializable]
        [DebuggerStepThrough]
        public abstract class CacheItem
        {
            #region Instance
            /// <summary>
            /// 初始化创建一个 <paramref name="CacheItem"/> 类的对象。
            /// </summary>
            public CacheItem()
            {
                MarkNew();
            }
    
            /// <summary>
            /// 初始化创建一个 <paramref name="CacheItem"/> 类的对象。
            /// </summary>
            /// <param name="isFetched"><c>true</c> 表示是从数据库中填充获得的; 否则返回 <c>false</c> </param>
            public CacheItem(bool isFetched)
            {
                if (isFetched)
                    MarkFetched();
                else
                    MarkNew();
            }
    
            /// <summary>
            /// 初始化创建一个 <paramref name="CacheItem"/> 类的对象。
            /// </summary>
            /// <param name="sessionID">会话标识</param>
            /// <param name="userID">用户标识</param>
            /// <param name="pageID">页面标识</param>
            /// <param name="dataID">数据标识</param>
            /// <returns>获得或新建的一个 <paramref name="CacheItem"/> 类的对象</returns>
            public CacheItem(string sessionID, string userID, string pageID, string dataID)
                : this()
            {
                SessionID = sessionID;
                UserID = userID;
                PageID = pageID;
                DataID = dataID;
            }
            #endregion
    
            #region Business Properties
            /// <summary>
            /// 获得或设置当前会话标识。
            /// </summary>
            public string SessionID { get; set; }
            /// <summary>
            /// 获得当前用户标识。
            /// </summary>
            public string UserID { get; set; }
            /// <summary>
            /// 获得或设置当前页面标识。
            /// </summary>
            public string PageID { get; set; }
            /// <summary>
            /// 获得或设置当前数据标识。
            /// </summary>
            public string DataID { get; set; }
    
            private byte[] _data = null;
            /// <summary>
            /// 获得或设置当前数据对象数据。
            /// </summary>
            public byte[] Data
            {
                get { return _data; }
                set
                {
                    _data = value;
                    IsDirty = true;
                }
            }
    
            /// <summary>
            /// 获得最近一次的修改时间
            /// </summary>
            public DateTime LastChanged { get; set; }
    
            /// <summary>
            /// 获得当前数据对象。
            /// </summary>
            public object DataObject
            {
                get { return Data == null ? null : Data.DeserializeFromByte<object>(); }
            }
            #endregion
    
            #region Mark Instance
            /// <summary>
            /// 获得当前实例是否是新建、未保存到数据库中。
            /// </summary>
            public bool IsNew { get; protected set; }
    
            /// <summary>
            /// 获得当前实例是否是否是从数据库中检索并填充的。
            /// </summary>
            public bool IsFetched { get; protected set; }
    
            /// <summary>
            /// 获得一个值, 通过该值指示当前实例对象是否被修改过。
            /// </summary>
            /// <value><c>true</c> 表示被修改过; 否则返回 <c>false</c> </value>
            public bool IsDirty { get; protected set; }
    
            /// <summary>
            /// 获得当前实例是否已经标识为删除。
            /// </summary>
            public bool IsDeleted { get; protected set; }
    
            /// <summary>
            /// 标识当前对象是新建、未保存到数据库中。
            /// </summary>
            /// <returns>更改后的自身。</returns>
            public CacheItem MarkNew()
            {
                IsDirty = false;
                IsNew = true;
                IsFetched = false;
                IsDeleted = false;
                return this;
            }
            /// <summary>
            /// 标识当前对象为从数据库中检索并填充的。
            /// </summary>
            /// <returns>更新后的自身。</returns>
            public CacheItem MarkFetched()
            {
                IsDirty = false;
                IsNew = false;
                IsFetched = true;
                IsDeleted = false;
                return this;
            }
            /// <summary>
            /// 标识当前实例对象需要在保存时删除。
            /// </summary>
            /// <returns>修改后的自身。</returns>
            public CacheItem MarkDeleted()
            {
                IsDirty = true;
                IsDeleted = true;
                return this;
            }
            #endregion
    
            #region Equal
            public override bool Equals(object obj)
            {
                if (obj == null || typeof(CacheItem) != obj.GetType())
                    return false;
    
                var target = obj as CacheItem;
                if (this.SessionID == target.SessionID &&
                    this.UserID == target.UserID &&
                    this.PageID == target.PageID &&
                    this.DataID == target.DataID)
                    return true;
    
                return base.Equals(obj);
            }
    
            public override int GetHashCode()
            {
                int hash = SessionID.GetHashCode();
                hash ^= UserID.GetHashCode();
                hash ^= PageID.GetHashCode();
                hash ^= DataID.GetHashCode();
    
                return hash;
            }
            #endregion
    
            #region Data Operater
            /// <summary>
            /// 持久化到数据库中。
            /// </summary>
            /// <param name="t">数据库操作实例对象</param>
            /// <returns>影响的行数。</returns>
            public abstract int Save(IDataAccesser t);
            #endregion
        }
    }

    在项目中我用 Sqlite 写了一个实现,具体代码如下:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using Lenic.Data;
    using Lenic.Data.Extensions;
    using System.Linq;
    
    using Lenic.Extensions;
    
    namespace Lenic.Web.Caches.Sqlite
    {
        /// <summary>
        /// 页面 ViewState 数据库缓冲
        /// </summary>
        [Serializable]
        [DebuggerStepThrough]
        public class SqliteCacheList : ICacheList
        {
            private List<SqliteCacheItem> list = new List<SqliteCacheItem>();
    
            #region DbHelper
            /// <summary>
            /// 缓存数据库连接字符串
            /// </summary>
            public static string ConnectionString = @"Data Source=|DataDirectory|\PageCache.dll";
    
            /// <summary>
            /// 数据库访问实例对象
            /// </summary>
            private static IDataAccesser DB = new DbHelper(DbProviders.SQLiteProvider, ConnectionString);
    
            /// <summary>
            /// 查询缓冲表是否在数据库中存在, 返回一个 <paramref name="System.Int64"/> 类型的值表示找到的个数.
            /// </summary>
            private const string SelectExists = "SELECT COUNT(*) AS COUNTS FROM SQLITE_MASTER WHERE TYPE = 'table' AND NAME = 'TB_Page'";
    
            /// <summary>
            /// 创建缓冲表语句.
            /// </summary>
            private const string CreateTable = @"CREATE TABLE [TB_Page] (
                                                     [SessionID] nvarchar(50) NOT NULL,
                                                     [UserID] nvarchar(50) NOT NULL,
                                                     [PageID] nvarchar(50) NOT NULL,
                                                     [DataID] nvarchar(50) NOT NULL,
                                                     [Data] blob,
                                                     [LastChanged] timestamp NOT NULL
                                                 )";
    
            /// <summary>
            /// 删除缓冲表语句.
            /// </summary>
            private const string DropTable = "Drop Table TB_Page";
    
            /// <summary>
            /// 收缩数据库语句.
            /// </summary>
            private const string ShrinkDB = "Vacuum";
    
            /// <summary>
            /// 清除用户之前的记录文本.
            /// </summary>
            private const string ClearPreviousText = "DELETE FROM [TB_Page] WHERE [UserID] = '{0}'";
    
            /// <summary>
            /// 清除指定 SessionID 指定用户的的记录文本.
            /// </summary>
            private const string ClearSessionText = "DELETE FROM [TB_Page] WHERE [SessionID] = {0} AND [UserID] = '{1}'";
    
            /// <summary>
            /// 【页面缓存】0 = 会话标识 AND 1 = 用户标识 AND 2 = 页面标识
            /// </summary>
            private const string SelectPageSql = "SELECT * FROM [TB_Page] WHERE [SessionID] = '{0}' AND [UserID] = '{1}' AND [PageID] = '{2}'";
    
            /// <summary>
            /// 【变量数据】0 = 会话标识 AND 1 = 用户标识 AND 2 = 页面标识 AND 3 = 数据标识
            /// </summary>
            private const string SelectSingleDataSql = "SELECT [Data] FROM [TB_Page] WHERE [SessionID] = '{0}' AND [UserID] = '{1}' AND [PageID] = '{2}' AND [DataID] = '{3}'";
            #endregion
    
            #region Business Properties
            /// <summary>
            /// 获得会话标识
            /// </summary>
            public string SessionID { get; private set; }
            /// <summary>
            /// 获得用户标识
            /// </summary>
            public string UserID { get; private set; }
            /// <summary>
            /// 获得页面标识
            /// </summary>
            public string PageID { get; private set; }
            #endregion
    
            #region New Instance
            private SqliteCacheList() { }
            /// <summary>
            /// 新建一个列表对象
            /// </summary>
            public static SqliteCacheList NewInstance(string sessionID, string userID, string pageID)
            {
                return new SqliteCacheList
                {
                    SessionID = sessionID,
                    UserID = userID,
                    PageID = pageID,
                };
            }
    
            /// <summary>
            /// 【自动新建】获得或设置缓存项。
            /// </summary>
            /// <value></value>
            /// <returns>缓存项</returns>
            public CacheItem this[int i]
            {
                get
                {
                    var item = list.ElementAtOrDefault(i);
                    if (item == null)
                    {
                        item = new SqliteCacheItem(SessionID, UserID, PageID, i.ToString());
                        list.Add(item);
                    }
                    return item;
                }
                set
                {
                    if (i >= list.Count)
                        list.Add((SqliteCacheItem)value);
                    else
                    {
                        list.RemoveAt(i);
                        list.Insert(i, (SqliteCacheItem)value);
                    }
                }
            }
            #endregion
    
            #region IEnumerable 成员
            /// <summary>
            /// 返回一个循环访问集合的枚举数。
            /// </summary>
            /// <returns>可用于循环访问集合的 System.Collections.Generic.IEnumeratorlt;SqliteCacheItemgt;。</returns>
            public IEnumerator<CacheItem> GetEnumerator()
            {
                var data = list.GetEnumerator();
                while (data.MoveNext())
                {
                    yield return (CacheItem)data.Current;
                }
            }
    
            /// <summary>
            /// 返回一个循环访问集合的枚举数。
            /// </summary>
            /// <returns>可用于循环访问集合的 System.Collections.Generic.IEnumeratorlt;SqliteCacheItemgt;。</returns>
            IEnumerator<CacheItem> IEnumerable<CacheItem>.GetEnumerator()
            {
                return this.GetEnumerator();
            }
    
            /// <summary>
            /// 返回一个循环访问集合的枚举数。
            /// </summary>
            /// <returns>可用于循环访问集合的 System.Collections.IEnumerator。</returns>
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }
            #endregion
    
            #region Data Operater
            /// <summary>
            /// 初始化缓冲数据库。
            /// </summary>
            /// <param name="deleteTable">如果设置为 <c>true</c> 标识先删除 Table 再重建。</param>
            public static void Init(bool deleteTable)
            {
                long count = 0;
                using (DataReaderEx con = DB.Read(SelectExists))
                {
                    count = con.Field<long>("COUNTS");
                }
    
                if (count > 0 && deleteTable)
                    DB.Write(DropTable);
                if (count == 0)
                    DB.Write(CreateTable);
                DB.Write(ShrinkDB);
            }
    
            /// <summary>
            /// 从数据库中清除用户旧的记录, 立即生效!
            /// </summary>
            /// <param name="userID">用户标识.</param>
            public static void ClearPrevious(string userId)
            {
                DB.Write(ClearPreviousText.With(userId));
            }
    
            /// <summary>
            /// 持久化数据变化
            /// </summary>
            public void Save()
            {
                using (var con = DbProviders.SQLiteProvider.CreateConnection())
                {
                    con.ConnectionString = ConnectionString;
                    con.Open();
                    var transaction = con.BeginTransaction();
    
                    var t = new TransactionHelper(transaction);
                    try
                    {
                        foreach (var item in this)
                        {
                            int count = item.Save(t);
                            if (count == 0)
                                throw new DatabaseException("数据库操作失败");
                        }
                        t.Commit();
                    }
                    catch (Exception e)
                    {
                        t.Rollback();
                        throw e;
                    }
                }
            }
    
            /// <summary>
            /// 从数据库中加载页面数据
            /// </summary>
            /// <param name="sessionId">会话标识</param>
            /// <param name="userId">用户标识</param>
            /// <param name="pageId">页面标识</param>
            /// <returns>加载后的列表</returns>
            public ICacheList LoadPageData()
            {
                if (SessionID.IsNullOrEmptyTrim())
                    throw new ApplicationException("会话标识不能为空");
                if (UserID.IsNullOrEmptyTrim())
                    throw new ApplicationException("用户标识不能为空");
                if (PageID.IsNullOrEmptyTrim())
                    throw new ApplicationException("页面标识不能为空");
    
                using (var con = DbProviders.SQLiteProvider.CreateConnection())
                {
                    con.ConnectionString = ConnectionString;
                    con.Open();
                    var transaction = con.BeginTransaction();
    
                    var t = new TransactionHelper(transaction);
                    try
                    {
                        using (DataReaderEx dr = t.Read(SelectPageSql.With(SessionID, UserID, PageID)))
                        {
                            list = dr.ToList<SqliteCacheItem>(p => new SqliteCacheItem(true)
                            {
                                SessionID = p.Field<string>("SessionID"),
                                UserID = p.Field<string>("UserID"),
                                PageID = p.Field<string>("PageID"),
                                DataID = p.Field<string>("DataID"),
                                Data = p.Field<byte[]>("Data"),
                                LastChanged = p.Field<DateTime>("LastChanged"),
                            });
                        }
                    }
                    finally
                    {
                        t.Rollback();
                    }
                }
                return this;
            }
    
            /// <summary>
            /// 从数据库中加载数据
            /// </summary>
            /// <typeparam name="T">数据的类型</typeparam>
            /// <param name="sessionId">会话标识</param>
            /// <param name="userId">用户标识</param>
            /// <param name="dataId">数据标识</param>
            /// <returns>还原的原始数据</returns>
            public T LoadData<T>(string dataId)
            {
                if (SessionID.IsNullOrEmptyTrim())
                    throw new ApplicationException("会话标识不能为空");
                if (UserID.IsNullOrEmptyTrim())
                    throw new ApplicationException("用户标识不能为空");
    
                var data = DB.GetValue(SelectSingleDataSql.With(SessionID, UserID, "Lenic.Global", dataId))
                             .DirectTo<byte[]>();
    
                if (data == null) return default(T);
                return data.DeserializeFromByte<T>();
            }
            #endregion
        }
    }

    下面是缓存项的实现类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    using Lenic.Data;
    using Lenic.Extensions;
    
    namespace Lenic.Web.Caches.Sqlite
    {
        /// <summary>
        /// Sqlite 缓存项
        /// </summary>
        [Serializable]
        [DebuggerStepThrough]
        public class SqliteCacheItem : CacheItem
        {
            #region Instance
            /// <summary>
            /// 初始化创建一个 <paramref name="SqliteCacheItem"/> 类的对象。
            /// </summary>
            public SqliteCacheItem()
            {
                MarkNew();
            }
    
            /// <summary>
            /// 初始化创建一个 <paramref name="SqliteCacheItem"/> 类的对象。
            /// </summary>
            /// <param name="isFetched"><c>true</c> 表示是从数据库中填充获得的; 否则返回 <c>false</c> </param>
            public SqliteCacheItem(bool isFetched)
            {
                if (isFetched)
                    MarkFetched();
                else
                    MarkNew();
            }
    
            /// <summary>
            /// 初始化创建一个 <paramref name="SqliteCacheItem"/> 类的对象。
            /// </summary>
            /// <param name="sessionID">会话标识</param>
            /// <param name="userID">用户标识</param>
            /// <param name="pageID">页面标识</param>
            /// <param name="dataID">数据标识</param>
            /// <returns>获得或新建的一个 <paramref name="SqliteCacheItem"/> 类的对象</returns>
            public SqliteCacheItem(string sessionID, string userID, string pageID, string dataID)
                : this()
            {
                SessionID = sessionID;
                UserID = userID;
                PageID = pageID;
                DataID = dataID;
            }
            #endregion
    
            #region Command Text
            /// <summary>
            /// 【插入】0 = 会话标识 AND 1 = 用户标识 AND 2 = 页面标识 AND 3 = 数据标识 AND 4 = 插入序号
            /// </summary>
            internal const string InsertText = "INSERT INTO [TB_Page]([SessionID], [UserID], [PageID], [DataID], [Data], [LastChanged]) Values('{0}', '{1}', '{2}', '{3}', @p{4}, datetime());";
            /// <summary>
            /// 【更新】0 = 会话标识 AND 1 = 用户标识 AND 2 = 页面标识 AND 3 = 数据标识 AND 4 = 更新序号
            /// </summary>
            internal const string UpdateText = "UPDATE [TB_Page] SET [Data] = @p{4}, [LastChanged] = datetime() WHERE [SessionID] = '{0}' AND [UserID] = '{1}' AND [PageID] = '{2}' AND [DataID] = '{3}'";
            /// <summary>
            /// 【删除】0 = 会话标识 AND 1 = 用户标识 AND 2 = 页面标识 AND 3 = 数据标识
            /// </summary>
            internal const string DeleteText = "Delete From [TB_Page] WHERE [SessionID] = '{0}' AND [UserID] = '{1}' AND [PageID] = '{2}' AND [DataID] = '{3}'";
            #endregion
    
            #region Data Operater
            /// <summary>
            /// 持久化到数据库中。
            /// </summary>
            /// <param name="t">数据库操作实例对象</param>
            /// <returns>影响的行数。</returns>
            public override int Save(IDataAccesser t)
            {
                if (IsNew && IsDeleted) return -1;
                if (!IsDirty) return -1;
                if (IsDeleted) return t.WriteD(DeleteText.With(SessionID, UserID, PageID, DataID));
                if (IsNew) return t.WriteD(InsertText.With(SessionID, UserID, PageID, DataID, 0), Data);
                if (IsFetched) return t.WriteD(UpdateText.With(SessionID, UserID, PageID, DataID, 0), Data);
    
                return 0;
            }
            #endregion
        }
    }

    就到这里吧,能拿出来的都拿出来了。后面的代码也包含了一些自定义方法,我略作解释:

    IDataAccesser 接口操作数据库,包含下面的方法,具体靠 DbHelper 和 TransactionHelper 实现,我就不写了,你应该能写出来一个实现类。很简单的!

    /// <summary>
    /// 数据库操作接口
    /// </summary>
    public interface IDataAccesser
    {
        /// <summary>
        /// 创建一个新的数据库命令对象。
        /// </summary>
        /// <returns>一个新的数据库命令对象。</returns>
        DbCommand NewCommand();
        /// <summary>
        /// 执行查询, 并返回查询所返回的结果集中第一行的第一列. 所有其他的列和行将被忽略.
        /// </summary>
        /// <param name="cmd">查询命令实例对象.</param>
        /// <returns>结果集中第一行的第一列.</returns>
        object GetValue(DbCommand cmd);
        /// <summary>
        /// 从数据库中查询并返回结果集(DataSet 类型)。
        /// </summary>
        /// <param name="cmd">查询命令实例对象。</param>
        /// <returns>查询结果集。</returns>
        DataSet Query(DbCommand cmd);
        /// <summary>
        /// 从数据库中查询并返回一个 <paramref name="System.Data.Common.DbDataReader"/> 类型的实例对象。
        /// </summary>
        /// <param name="cmd">查询命令实例对象。</param>
        /// <returns>查询结果集。</returns>
        DbDataReader Read(DbCommand cmd);
        /// <summary>
        /// 执行数据库操作, 并返回影响的行数。
        /// </summary>
        /// <param name="cmd">执行命令实例对象。</param>
        /// <returns>影响的行数。</returns>
        int Write(DbCommand cmd);
    }

    DataReaderEx 是 DbDataReader 的一个实现类,用修饰模式实现,这里你可以把其当成 IDataReader 接口来看待。

    IsNullOrEmptyTrim 是对 String 类 IsNullOrEmpty 方法的封装,同时增加了对 Trim 方法处理后的判断。

    DirectTo 是对类型强转的包装,等于 (T)obj 。

    With 是对 String.Format 的封装。

  • 相关阅读:
    集训队作业2018人类的本质
    推式子小技巧
    [Codeforces671D]Roads in Yusland
    线性规划的对偶问题
    数学虐哭空巢老人记
    Voronoi图与Delaunay三角剖分
    [ZJOI2018]保镖
    [SPOJ2939]Qtree5
    数据结构虐哭空巢老人记
    [CTSC2006]歌唱王国
  • 原文地址:https://www.cnblogs.com/lenic/p/2177331.html
Copyright © 2011-2022 走看看