zoukankan      html  css  js  c++  java
  • 程序员的自我救赎---1.4.1:核心框架讲解(DAL)

    《前言》

    (一) Winner2.0 框架基础分析

    (二)PLSQL报表系统

    (三)SSO单点登录

    (四) 短信中心与消息中心

    (五)钱包系统

    (六)GPU支付中心

    (七)权限系统

    (八)监控系统

    (九)会员中心

    (十) APP版本控制系统

    (十一)Winner前端框架与RPC接口规范讲解

    (十二)上层应用案例

    (十三)总结

    《核心框架讲解》

    之前在《Winner2.0框架解决方案命分层规范》 有讲到过Winner框架最重要的三个程序集分别是:

    Winner.Framework.Core       (核心类dll)
    Winner.Framework.Encrypt   (加密类dll)
    Winner.Framework.Utils         (工具类dll)
     
    这三个死核心类库,每一层都引用这三个程序集。如果是做MVC的web开发我们还会有一个Winner.Framework.MVC   (前端dll)
     每一层都继承框架的基类如下:
     

    DataAcces: 继承  “DataAccessBase”

    Entities: 没有单独可基础的核心框架类,可直接引用工具类     

    Facade:      继承:“FacadeBase”

    APP(MVC):  继承:“TopControllerBase”

    我们重点讲一下,“DataAccessBase”,“FacadeBase”,“TopControllerBase” 这三个基类。

    其实前面在 《代码生成器的使用》和《事务的使用》两篇文章中就分别讲到过“DataAccessBase” 和 "FacadeBase"  。

    我们先来分析DataAccessBase我们看一下在我们真实开发中关于数据库访问代码的的使用。建议复制到VS中去看,不然在博客中确实不好看懂。

    /***********************代码生成器生成的 充值表数据操作************
    *
    * Data Access Layer Of Winner Framework
    * FileName : Tdct_Recharge.generate.cs 
    * Version : V 1.1.0
    * Author:架构师 曾杰(Jie)
    * E_Mail : 6e9e@163.com
    * Tencent QQ:554044818
    * Blog : http://www.cnblogs.com/fineblog/
    * CreateTime : 2017-10-11 18:06:04  
    * 
    ***************************************************/
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Text;
    using Winner.Framework.Core;
    using Winner.Framework.Core.DataAccess;
    using Winner.Framework.Core.DataAccess.Oracle;
    using Winner.Framework.Utils;
    using Winner.DCTS.Entities;
    namespace Winner.DCTS.DataAccess
    {
        /// <summary>
        /// Data Access Layer Object Of Tdct_Recharge
        /// </summary>
        public partial class Tdct_Recharge : DataAccessBase
        {
            #region 默认构造
    
            public Tdct_Recharge() : base() { }
    
            public Tdct_Recharge(DataRow dataRow)
                : base(dataRow) { }
    
            #endregion 默认构造
    
            #region 对应表结构的常量属性
            
            public const string _RECHARGE_ID="RECHARGE_ID";
            public const string _PAY_TYPE="PAY_TYPE";
            public const string _AMOUNT="AMOUNT";
            public const string _ACCOUNT="ACCOUNT";
            public const string _USER_ID="USER_ID";
            public const string _STATUS="STATUS";
            public const string _CREATE_TIME="CREATE_TIME";
            public const string _REMARKS="REMARKS";
    
        
            public const string _TABLENAME="Tdct_Recharge";
            #endregion 对应表结构的常量属性
    
            #region 公开属性
            
            /// <summary>
            /// 充值记录ID
            /// [default:0]
            /// </summary>
            public int RechargeId
            {
                get { return Convert.ToInt32(DataRow[_RECHARGE_ID]); }
                set { setProperty(_RECHARGE_ID,value); }
            }
            /// <summary>
            /// 支付类型 1支付宝,2银行卡,3微信
            /// [default:0]
            /// </summary>
            public int PayType
            {
                get { return Convert.ToInt32(DataRow[_PAY_TYPE]); }
                set { setProperty(_PAY_TYPE,value); }
            }
            /// <summary>
            /// 充值金额
            /// [default:0]
            /// </summary>
            public decimal Amount
            {
                get { return Convert.ToDecimal(DataRow[_AMOUNT]); }
                set { setProperty(_AMOUNT,value); }
            }
            /// <summary>
            /// 充值账号
            /// [default:string.Empty]
            /// </summary>
            public string Account
            {
                get { return DataRow[_ACCOUNT].ToString(); }
                set { setProperty(_ACCOUNT,value); }
            }
            /// <summary>
            /// 充值用户
            /// [default:0]
            /// </summary>
            public int UserId
            {
                get { return Convert.ToInt32(DataRow[_USER_ID]); }
                set { setProperty(_USER_ID,value); }
            }
            /// <summary>
            /// 充值状态 0等待银行到账,1已经到账,2操作失败
            /// [default:0]
            /// </summary>
            public RechargeStatus Status
            {
                get { return (RechargeStatus)Convert.ToInt32(DataRow[_STATUS]); }
                set { setProperty(_STATUS,(int)value); }
            }
            /// <summary>
            /// 充值时间
            /// [default:new DateTime()]
            /// </summary>
            public DateTime CreateTime
            {
                get { return Convert.ToDateTime(DataRow[_CREATE_TIME].ToString()); }
            }
            /// <summary>
            /// 备注
            /// [default:string.Empty]
            /// </summary>
            public string Remarks
            {
                get { return DataRow[_REMARKS].ToString(); }
                set { setProperty(_REMARKS,value); }
            }
    
            #endregion 公开属性
            
            #region 私有成员
            
            protected override string TableName
            {
                get { return _TABLENAME; }
            }
    
            protected override DataRow BuildRow()
            {
                DataTable dt = new DataTable(_TABLENAME);
                dt.Columns.Add(_RECHARGE_ID, typeof(int)).DefaultValue = 0;
                dt.Columns.Add(_PAY_TYPE, typeof(int)).DefaultValue = 0;
                dt.Columns.Add(_AMOUNT, typeof(decimal)).DefaultValue = 0;
                dt.Columns.Add(_ACCOUNT, typeof(string)).DefaultValue = string.Empty;
                dt.Columns.Add(_USER_ID, typeof(int)).DefaultValue = 0;
                dt.Columns.Add(_STATUS, typeof(int)).DefaultValue = 0;
                dt.Columns.Add(_CREATE_TIME, typeof(DateTime)).DefaultValue = new DateTime();
                dt.Columns.Add(_REMARKS, typeof(string)).DefaultValue = string.Empty;
    
                return dt.NewRow();
            }
            
            #endregion 私有成员
            
            #region 常用方法
            
            protected bool DeleteByCondition(string condition)
            {
                string sql = @"DELETE FROM TDCT_RECHARGE WHERE " + condition;
                return base.DeleteBySql(sql);
            }
            
            public bool Delete(int rechargeId)
            {
                string condition = "RECHARGE_ID=:RECHARGE_ID";
                AddParameter(_RECHARGE_ID, rechargeId);
                return DeleteByCondition(condition);
            }
            
            public bool Delete()
            {
                string condition = "RECHARGE_ID=:RECHARGE_ID";
                AddParameter(_RECHARGE_ID, RechargeId);
                return DeleteByCondition(condition);
            }
    
            public bool Insert()
            {
                RechargeId=base.GetSequence("SELECT SEQ_TDCT_RECHARGE.NEXTVAL FROM DUAL");
    string sql=@"INSERT INTO
    TDCT_RECHARGE(
      RECHARGE_ID,
      PAY_TYPE,
      AMOUNT,
      ACCOUNT,
      USER_ID,
      STATUS,
      REMARKS)
    VALUES(
      :RECHARGE_ID,
      :PAY_TYPE,
      :AMOUNT,
      :ACCOUNT,
      :USER_ID,
      :STATUS,
      :REMARKS)";
                AddParameter(_RECHARGE_ID,DataRow[_RECHARGE_ID]);
                AddParameter(_PAY_TYPE,DataRow[_PAY_TYPE]);
                AddParameter(_AMOUNT,DataRow[_AMOUNT]);
                AddParameter(_ACCOUNT,DataRow[_ACCOUNT]);
                AddParameter(_USER_ID,DataRow[_USER_ID]);
                AddParameter(_STATUS,DataRow[_STATUS]);
                AddParameter(_REMARKS,DataRow[_REMARKS]);
                return base.InsertBySql(sql);
            }
            
            public bool Update()
            {
                return UpdateByCondition(string.Empty);
            }
            
            protected bool UpdateByCondition(string condition)
            {
                //移除主键标记
                ChangePropertys.Remove(_RECHARGE_ID);
                
                if (ChangePropertys.Count == 0)
                {
                    return true;
                }
                
                StringBuilder sql = new StringBuilder();
                sql.AppendLine("UPDATE TDCT_RECHARGE SET");
                while (ChangePropertys.MoveNext())
                {
                     sql.AppendFormat(" {0}{1}=:{1} ", (ChangePropertys.CurrentIndex == 0 ? string.Empty : ","), ChangePropertys.Current);
                    AddParameter(ChangePropertys.Current, DataRow[ChangePropertys.Current]);
                }
                sql.AppendLine(" WHERE RECHARGE_ID=:RECHARGE_ID");
                AddParameter(_RECHARGE_ID, DataRow[_RECHARGE_ID]);
                if (!string.IsNullOrEmpty(condition))
                    sql.AppendLine(" AND " + condition);
                    
                bool result = base.UpdateBySql(sql.ToString());
                ChangePropertys.Clear();
                return result;
            }
    
            protected bool SelectByCondition(string condition)
            {
                string sql = @"
    SELECT
      RECHARGE_ID,
      PAY_TYPE,
      AMOUNT,
      ACCOUNT,
      USER_ID,
      STATUS,
      CREATE_TIME,
      REMARKS
    FROM TDCT_RECHARGE
    WHERE " + condition;
                return base.SelectBySql(sql);
            }
    
            public bool SelectByPK(int rechargeId)
            {
                string condition = "RECHARGE_ID=:RECHARGE_ID";
                AddParameter(_RECHARGE_ID, rechargeId);
                return SelectByCondition(condition);
            }
            public Tnet_User Get_Tnet_User_ByUserId()
            {
                Tnet_User da=new Tnet_User();
                da.SelectByPK(UserId);
                return da;
            }
    
    
    
            #endregion 常用方法
            
            //提示:此类由代码生成器生成,如无特殊情况请不要更改。如要扩展请在外部同名类中扩展
        }
        
        /// <summary>
        /// Data Access Layer Object Collection Of Tdct_Recharge
        /// </summary>
        public partial class Tdct_RechargeCollection : DataAccessCollectionBase
        {
            #region 默认构造
     
            public Tdct_RechargeCollection() { }
    
            public Tdct_RechargeCollection(DataTable table)
                : base(table) { }
                
            #endregion 默认构造
            
            #region 私有成员
            protected override DataAccessBase GetItemByIndex(int index)
            {
                return new Tdct_Recharge(DataTable.Rows[index]);
            }
            
            protected override DataTable BuildTable()
            {
                return new  Tdct_Recharge().CloneSchemaOfTable();
            }
            
            protected override string TableName
            {
                get { return Tdct_Recharge._TABLENAME; }
            }
            
            protected bool ListByCondition(string condition)
            {
                string sql = @"
    SELECT
      RECHARGE_ID,
      PAY_TYPE,
      AMOUNT,
      ACCOUNT,
      USER_ID,
      STATUS,
      CREATE_TIME,
      REMARKS
    FROM TDCT_RECHARGE
    WHERE " + condition;
                return base.ListBySql(sql);
            }
    
            public bool ListByRechargeId(int rechargeId)
            {
                string condition = "RECHARGE_ID=:RECHARGE_ID";
                AddParameter(Tdct_Recharge._RECHARGE_ID, rechargeId);
                return ListByCondition(condition);
            }
    
            public bool ListAll()
            {
                string condition = "1=1";
                return ListByCondition(condition);
            }
            
            public bool DeleteByCondition(string condition)
            {
                string sql = "DELETE FROM TDCT_RECHARGE WHERE " + condition;
                return DeleteBySql(sql);
            }
            #endregion
            
            #region 公开成员
            public Tdct_Recharge this[int index]
            {
                get
                {
                    return new Tdct_Recharge(DataTable.Rows[index]);
                }
            }
    
            public bool DeleteAll()
            {
                return this.DeleteByCondition(string.Empty);
            }
            
            #region Linq
            
            public Tdct_Recharge Find(Predicate<Tdct_Recharge> match)
            {
                foreach (Tdct_Recharge item in this)
                {
                    if (match(item))
                        return item;
                }
                return null;
            }
            public Tdct_RechargeCollection FindAll(Predicate<Tdct_Recharge> match)
            {
                Tdct_RechargeCollection list = new Tdct_RechargeCollection();
                foreach (Tdct_Recharge item in this)
                {
                    if (match(item))
                        list.Add(item);
                }
                return list;
            }
            public bool Contains(Predicate<Tdct_Recharge> match)
            {
                foreach (Tdct_Recharge item in this)
                {
                    if (match(item))
                        return true;
                }
                return false;
            }
    
            public bool DeleteAt(Predicate<Tdct_Recharge> match)
            {
                BeginTransaction();
                foreach (Tdct_Recharge item in this)
                {
                    item.ReferenceTransactionFrom(Transaction);
                    if (!match(item))
                        continue;
                    if (!item.Delete())
                    {
                        Rollback();
                        return false;
                    }
                }
                Commit();
                return true;
            }
            #endregion Linq
            #endregion
            
            //提示:此类由代码生成器生成,如无特殊情况请不要更改。如要扩展请在外部同名类中扩展
        }
    } 
    /***********************由技术员编写****************************
    *
    * Data Access Layer Of Winner Framework
    * FileName : Tdct_Recharge.extension.cs 
    * Version : V 1.1.0
    * Author:架构师 曾杰(Jie)
    * E_Mail : 6e9e@163.com
    * Tencent QQ:554044818
    * Blog : http://www.cnblogs.com/fineblog/
    * CreateTime : 2017-10-11 17:55:39  
    * 
    ***************************************************/
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Text;
    using Winner.Framework.Core;
    using Winner.Framework.Core.DataAccess;
    using Winner.Framework.Core.DataAccess.Oracle;
    using Winner.Framework.Utils;
    using Winner.DCTS.Entities;
    using Winner.DCTS.Entities.enums;
    
    namespace Winner.DCTS.DataAccess
    {
        /// <summary>
        /// Data Access Layer Object Of Tdct_Recharge
        /// </summary>
        public partial class Tdct_Recharge : DataAccessBase
        {
            //Custom Extension Class
            public bool Delete(int rechargeId, int userId)
            {
                string condition = "RECHARGE_ID=:RECHARGE_ID AND USER_ID=:USER_ID AND STATUS=0";
                AddParameter(_RECHARGE_ID, rechargeId);
                AddParameter(_USER_ID, userId);
                return DeleteByCondition(condition);
            }
    
            public bool SelectById(int rechargeId)
            {
                string condition = "RECHARGE_ID=:RECHARGE_ID AND STATUS=:STATUS";
                AddParameter(_RECHARGE_ID, rechargeId);
                AddParameter(_STATUS, RechargeStatus.等待充值.GetHashCode());
                return SelectByCondition(condition);
            }
        }
    
        /// <summary>
        /// Data Access Layer Object Collection Of Tdct_Recharge
        /// </summary>
        public partial class Tdct_RechargeCollection : DataAccessCollectionBase
        {
            public bool ListByUserId(int userId)
            {
                string condition = " USER_ID = :USER_ID ORDER BY RECHARGE_ID DESC ";
                AddParameter("USER_ID", userId);
                return ListByCondition(condition);
            }
    
            /// <summary>
            /// 查询列表
            /// </summary>
            /// <param name="status"></param>
            /// <param name="paytype"></param>
            /// <returns></returns>
            public bool ListByKeyWord(string keyword,int status,int paytype)
            {
                string sql = "SELECT TR.*,VU.USER_CODE,VU.USER_NAME FROM TDCT_RECHARGE TR JOIN VNET_USER VU ON TR.USER_ID=VU.USER_ID  WHERE 1=1 ";
    
                if(!string.IsNullOrEmpty(keyword))
                {
                    sql += " AND( TR.ID=:ID";
                    sql += " OR VU.USER_NAME=:USERNAME)";
                    AddParameter("ID", keyword);
                    AddParameter("USERNAME", keyword);
                }
    
                if (status>=0)
                {
                    sql += " AND TR.STATUS=:STATUS";
                    AddParameter("STATUS", status);
                }
    
                if(paytype>=0)
                {
                    sql += " AND TR.PAY_TYPE=:PAYTYPE";
                    AddParameter("PAYTYPE",paytype);
                }
    
                sql += " ORDER BY TR.RECHARGE_ID DESC";
    
                return ListBySql(sql);
            }
    
            //Custom Extension Class
        }
    }

    对于项目结构不理解的需要先看《Winner2.0框架解决方案命分层规范》  才能看懂,为什么我们会这样写。 我想了想关于DataAccessBase,我们还是又浅入深的去讲。

    先从最最简单的 AddParameter() 这个方法开始讲起,明眼一看就知道这是一个 “参数化” 传值,至于参数化传值有什么好处就自行百度吧,我看到很多公司的项目本身可以封装

    一层参数化方法,但是却“痴迷”于用 存储过程 却解决参数化问题,然后放大存储过程“预编译”的优势,其实这个没有必要。无论是哪种数据库都是支持C# 参数化 操作的。

    我们看看AddParameter() 这个方法是怎么实现的:

       #region AddParameter
    
            /// <summary>
            /// 添加DAO.NET的SqlCommand命令对象参数
            /// </summary>
            /// <param name="parameterName">参数名称</param>
            /// <param name="value">参数值</param>
            protected DbParameter AddParameter(string parameterName, object value)
            {
                if (string.IsNullOrEmpty(parameterName))
                {
                    throw new Exception("传入的参数名称为空");
                }
                if (string.IsNullOrEmpty(DBFactory.ParameterSign))
                {
                    throw new Exception("未指定参数符合(例如:Oracle::、SqlServer:@....)");
                }
                if (!parameterName.StartsWith(this.DBFactory.ParameterSign))
                {
                    parameterName = this.DBFactory.ParameterSign + parameterName;
                }
                DbParameter parm = DBFactory.DBProvider.CreateParameter();
                parm.ParameterName = parameterName;
                parm.Value = value;
                AddParameter(parm);
                return parm;
            }
    
            /// <summary>
            /// 添加DAO.NET的SqlCommand命令对象参数
            /// </summary>
            /// <param name="parameterName">参数名称</param>
            /// <param name="direction">参数模式</param>
            /// <param name="func">处理返回值函数</param>
            /// <example>
            /// <code>
            /// <![CDATA[
            /// //接收的参数
            /// int id;
            /// AddParameter("Id", ParameterDirection.ReturnValue, value => id = value.ConvertTo<int>());
            /// ]]>
            /// </code>
            /// </example>
            protected DbParameter AddParameter(string parameterName, ParameterDirection direction, Func<DbParameter, object> func)
            {
                if (string.IsNullOrEmpty(parameterName))
                {
                    throw new Exception("传入的参数名称为空");
                }
                if (string.IsNullOrEmpty(DBFactory.ParameterSign))
                {
                    throw new Exception("未指定参数符合(例如:Oracle::、SqlServer:@....)");
                }
                if (!parameterName.StartsWith(this.DBFactory.ParameterSign))
                {
                    parameterName = this.DBFactory.ParameterSign + parameterName;
                }
                DbParameter parm = DBFactory.DBProvider.CreateParameter();
                parm.ParameterName = parameterName;
                parm.Direction = direction;
                parm.Value = string.Empty;
                parm.Size = 2000;
                AddParameter(parm);
                Parameters.OutValuesParamerer.Add(parm, func);
                return parm;
            }
    
            /// <summary>
            /// 添加DAO.NET的SqlCommand命令对象参数
            /// </summary>
            /// <param name="parameterName">参数名称</param>
            /// <param name="func">处理返回值函数</param>
            /// <example>
            /// <code>
            /// <![CDATA[
            /// //接收的参数
            /// int id;
            /// AddParameter("Id", value => id = value.ConvertTo<int>());
            /// ]]>
            /// </code>
            /// </example>
            protected DbParameter AddParameter(string parameterName, Func<DbParameter, object> func)
            {
                return AddParameter(parameterName, ParameterDirection.Output, func);
            }
            /// <summary>
            /// 添加DAO.NET的SqlCommand命令对象参数
            /// </summary>
            /// <param name="parm">参数</param>
            protected DbParameter AddParameter(DbParameter parm)
            {
                if (this.Parameters == null)
                {
                    this.Parameters = new ParameterCollection(DBFactory.DBProvider);
                }
                DbParameter item = this.Parameters.Find(s => s.ParameterName == parm.ParameterName);
                if (item != null)
                {
                    this.Parameters.Remove(item);
                }
                this.Parameters.Add(parm);
                return parm;
            }
            #endregion

     每种数据库语法的不同,对应的参数化符合自然不同。Sqlerver是用“@”,Oracle是用“:”。这里阿杰用了“工厂模式”来解决这个问题。

     

     这里我们贴出OracleProvider.cs类来作为示例:

    using System.Configuration;
    using System.Data.Common;
    using System.Data.OracleClient;
    using Winner.Framework.Core.CustomException;
    using Winner.Framework.Utils;
    
    namespace Winner.Framework.Core.DataAccess.Oracle
    {
        /// <summary>
        /// Oracle 配置工厂
        /// </summary>
        internal class OracleProvider : DBFactory
        {
            private OracleProvider() { }
    
            //static OracleFactory() { }
    
            /// <summary>
            /// Oracle操作工厂实例
            /// </summary>
            public static readonly OracleProvider Instance = new OracleProvider();
    
            /// <summary>
            /// 数据库工厂
            /// </summary>
            internal override DbProviderFactory DBProvider
            {
                get { return OracleClientFactory.Instance; }
            }
    
            /// <summary>
            /// 数据库连接字符串
            /// </summary>
            internal override string GetConnectionString()
            {
                ConnectionStringSettings conn = ConfigurationManager.ConnectionStrings["Winner.Framework.Oracle.ConnectionString"];
                if (conn == null)
                {
                    ConnectionStringException ex = new ConnectionStringException("AppConfig.ConnectionStrings节点未配置Winner.Framework.Oracle.ConnectionString连接字符串");
                    throw ex;
                }
                return conn.ConnectionString;
            }
    
            /// <summary>
            /// 参数标识符
            /// </summary>
            public override string ParameterSign
            {
                get
                {
                    return ":";
                }
            }
    
            /// <summary>
            /// 通用数据库的SQL语句帮助类
            /// </summary>
            public override SQLHelper SQLHelper
            {
                get { return SQLHelperProvider.Instance; }
            }
        }
    }
    

      

    还有工厂类的代码: 

    using System;
    using System.Data.Common;
    using Winner.Framework.Core.CustomException;
    using Winner.Framework.Utils;
    
    namespace Winner.Framework.Core.DataAccess
    {
        /// <summary>
        ///  配置工厂
        /// </summary>
        public abstract class DBFactory
        {
            /// <summary>
            /// 数据库工厂
            /// </summary>
            internal abstract DbProviderFactory DBProvider { get; }
    
            private string _connectionString;
            /// <summary>
            /// 数据库连接字符串
            /// </summary>
            internal string ConnectionString
            {
                get
                {
                    if (string.IsNullOrEmpty(_connectionString))
                    {
                        string temp = GetConnectionString();
                        if (temp.Empty())
                        {
                            var connectionStringException = new ConnectionStringException("未获取到数据库连接字符串");
                            Log.Error(connectionStringException);
                            throw connectionStringException;
                        }
                        if (AppSettingsProvider.ConnectionStringEncrypt)
                        {
                            try
                            {
                                temp = Winner.Framework.Encrypt.Hardware.Decode(temp);
                            }
                            catch (Exception ex)
                            {
                                Log.Warn("配置字符串:" + temp);
                                var connectionStringException = new ConnectionStringException("数据库连接字符串解密失败,请确保硬件设备已分配权限,请联系架构师Jie[QQ:554044818]!" + ex.Message, ex);
                                Log.Error(connectionStringException);
                                throw connectionStringException;
                            }
                        }
                        _connectionString = temp;
                    }
                    return _connectionString;
                }
            }
    
            /// <summary>
            /// 设置连接字符串
            /// </summary>
            /// <param name="str"></param>
            public void SetConnectionString(string str)
            {
                _connectionString = str;
            }
            /// <summary>
            /// 重置连接字符串
            /// </summary>
            public void ResetConnectionString()
            {
                _connectionString = GetConnectionString();
            }
            /// <summary>
            /// 设置连接字符串
            /// </summary>
            internal abstract string GetConnectionString();
    
            /// <summary>
            /// 参数标识符号
            /// </summary>
            public abstract string ParameterSign { get; }
    
            /// <summary>
            /// SQL 帮助类
            /// </summary>
            public abstract SQLHelper SQLHelper { get; }
        }
    }

     在我们团队内部属于严格要求必须使用参数化。在此之前我们会使用SQL拼接,当然框架现在也是支持参数拼接的,只是拼接在防sql注入上需要严谨对待,下面我

    贴一下,框架封装的sql拼接工具类:

    using System;
    using System.Drawing;
    using System.IO;
    using Winner.Framework.Encrypt;
    namespace Winner.Framework.Core.DataAccess
    {
        /// <summary>
        /// 通用数据库的SQL语句帮助类
        /// </summary>
        public abstract class SQLHelper
        {
            /// <summary>
            /// 此类作为静态方式使用不能在其他程序集实例化
            /// </summary>
            internal SQLHelper()
            {
            }
    
            /// <summary>
            /// 美化SQL,去掉	
    
    及多余空格
            /// </summary>
            /// <param name="sql">SQL语句</param>
            /// <returns></returns>
            public string BeautifulSql(string sql)
            {
                sql = sql.Replace("
    ", " ").Replace("	", " ").Replace("
    ", " ");
                while (sql.IndexOf("  ") >= 0)
                {
                    sql = sql.Replace("  ", " ");
                }
                sql = sql.Replace(", ", ",");
                return sql.Trim();
            }
    
            /// <summary>
            /// SQL参数 敏感处理
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
            private string SQLParameterHandle(object obj)
            {
                string value = string.Empty;
                if (obj == null)
                {
                    return string.Empty;
                }
                value = obj.ToString().Replace("
    ", " ").Replace("	", " ").Replace("
    ", " ");
                while (value.IndexOf("  ") >= 0)
                {
                    value = value.Replace("  ", " ");
                }
                return value.Replace(", ", ",").Replace("'", "''");
            }
    
            /// <summary>
            /// 转换为SQL参数字符串,如:123 转换成 '123'
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
            public string ToSQLParameter(object obj)
            {
                string value = SQLParameterHandle(obj);
                return string.Format("'{0}'", value);
            }
    
            /// <summary>
            /// 按时间查询的Berween And 语句,如:Age Between 15 ADN 18
            /// </summary>
            /// <param name="columnName">根据查询的列</param>
            /// <param name="begTime">开始时间</param>
            /// <param name="endTime">结束时间</param>
            /// <returns>String类型的SQL语句</returns>
            public string ToSQLBetween(string columnName, DateTime begTime, DateTime endTime)
            {
                return string.Format(" {0} Between {1} ADN {2} ", columnName, begTime, endTime);
            }
    
            /// <summary>
            /// 转换为左Like语句,如:UserName like '%杰'
            /// </summary>
            /// <param name="columnName">列名</param>
            /// <param name="Value"></param>
            /// <returns></returns>
            public string ToSQLLeftLike(string columnName, string Value)
            {
                return string.Format(" {0} like '%{1}'", columnName, SQLParameterHandle(Value));
            }
    
            /// <summary>
            /// 转换为Like语句,如:UserName like '%杰%'
            /// </summary>
            /// <param name="columnName">列名</param>
            /// <param name="Value"></param>
            /// <returns></returns>
            public string ToSQLLike(string columnName, string Value)
            {
                return string.Format(" {0} like '%{1}%'", columnName, SQLParameterHandle(Value));
            }
    
            /// <summary>
            /// 转换为右Like语句,如:UserName like '杰%'
            /// </summary>
            /// <param name="columnName">列名</param>
            /// <param name="Value"></param>
            /// <returns></returns>
            public string ToSQLRightLike(string columnName, string Value)
            {
                return string.Format(" {0} like '{1}%'", columnName, SQLParameterHandle(Value));
            }
    
            #region To SQL Date
    
            /// <summary>
            /// 按时间查询的Berween And 语句
            /// </summary>
            /// <param name="columnName">根据查询的列</param>
            /// <param name="beginDate">开始时间</param>
            /// <param name="endDate">结束时间</param>
            /// <returns>String类型的SQL语句</returns>
            public abstract string ToSQLBetweenDate(string columnName, DateTime beginDate, DateTime endDate);
    
            /// <summary>
            /// 按时间查询的Berween And 语句
            /// </summary>
            /// <param name="columnName">根据查询的列</param>
            /// <param name="beginDate">开始时间</param>
            /// <param name="endDate">结束时间</param>
            /// <returns>String类型的SQL语句</returns>
            public abstract string ToSQLBetweenDateTime(string columnName, DateTime beginDate, DateTime endDate);
    
            /// <summary>
            /// 转换为SQL语句中的日期类型,格式如:2009-05-18
            /// </summary>
            /// <param name="obj">需要转换为SQL类型的值</param>
            /// <returns></returns>
            public abstract string ToSQLDate(object obj);
    
            /// <summary>
            /// 转换为SQL语句类型的时间格式,如2010-03-04 12:12:12
            /// </summary>
            /// <param name="obj">需要转换为SQL类型的值</param>
            /// <returns></returns>
            public abstract string ToSQLDateTime(object obj);
    
            /// <summary>
            /// 转换为当天范围SQL语句
            /// </summary>
            /// <param name="columnName">字段名称</param>
            /// <param name="date">日期</param>
            /// <returns></returns>
            public abstract string ToSQLInduriteDate(string columnName, DateTime date);
            #endregion
        }
    }

    注意这里,sqlhelp是个工具类,其中因为各个数据库的语法不同,我们部分拼接方法需要重新实现抽象类比如:ToSQLBetweenDate();

    SqlServer 写法:

      public override string ToSQLBetweenDate(string FieldName, DateTime beginDate, DateTime endDate)
            {
                return string.Format(" {0} Between Convert(DateTime,'{1}') and Convert(DateTime,'{2}') ", FieldName, beginDate.ToString("yyyy-MM-dd"), endDate.ToString("yyyy-MM-dd"));
            }

    Oracle 写法:

        public override string ToSQLBetweenDate(string FieldName, DateTime beginDate, DateTime endDate)
            {
                return string.Format("({0} BETWEEN TO_DATE('{1}','YYYY-MM-DD') AND TO_DATE('{2}','YYYY-MM-DD'))", FieldName, beginDate.ToString("yyyy-MM-dd"), endDate.ToString("yyyy-MM-dd"));
            }

     

    关于DataAccess最重要的职责是负责与数据库通讯,当然这里我就不去讲述是如何实现的了,看了上面那个AddParameter()的讲解之后

    里面贴的代码就已经讲述了,如何链接数据库。 而看了我们的SqlHelp之后自然也就能了解我们的“增删查改”是怎么实现了的,

    其实很简单.

    DataAccessBase :DataAccessCore

    DataAccessCore:DataProviderBase

    写到这里其实贴的代码多了,有点眼花缭乱的。 我们还是回归到由浅入深的思路去讲解,其实作为使用者到这里就不必过分深究如何实现“增删查改”每一个方法。 

    接下来我写一下关于DataAccess 另外好用的功能,如果说之前写的事务能Winner框架中最好用的功能,那下面这个功能就可以算的上是第二好用的功能----“分页”

    在接触Winner之前,我最常用的是从学校学的那个“分页存储过程”。先不说好用不好用,以动软例总之每个列表要单独处理分页。(也许是我没用好)但是在Winner

    里面很简单。贴一下我们是怎么用的:

     是的,我们只要设置DA的Changepage这个对象即可。 Winner在控制上用了一个“扩展类”,不清楚扩展类的就要自行百度一下了。

     

    回到前面,可以看到代码生成器生成的集合类操作我们是需要继承 “DataAccessCollectionBase”  而 DataAccessCollectionBase:DataAccessCollectionCore

     DataAccessCollectionCore 里我们定义了一个分页对象 ChangePage

    ChangePage 实现了 IChangePage 接口,准确来说任何实现了IChangePage的对象都可以使用我们的分页插件。

    ChangePage 就是一个分页对象。

    /***************************************************
    *
    * Create Time : 2014/9/1 11:38:37 
    * Version : V 1.01
    * Create User:Jie
    * E_Mail : 6e9e@163.com
    * 
    ***************************************************/
    using Winner.Framework.Core.Interface;
    
    namespace Winner.Framework.Core.DataAccess
    {
        /// <summary>
        /// 分页控件适配器
        /// </summary>
        public class ChangePage : IChangePage
        {
            /// <summary>
            /// 分页语句类型
            /// </summary>
            public QueryCommandType CommandType { get; set; }
    
            /// <summary>
            /// 总行数
            /// </summary>
            public int Count { get; set; }
    
            /// <summary>
            /// 当前页面
            /// </summary>
            public int CurrentPageIndex { get; set; }
    
            /// <summary>
            /// 每页显示行数
            /// </summary>
            public int PageSize { get; set; }
    
            /// <summary>
            /// 排序字段名称
            /// </summary>
            public string SortFields { get; set; }
    
            /// <summary>
            /// 排序顺序
            /// </summary>
            public SortType SortType { get; set; }
    
            /// <summary>
            /// 构造新的适配器
            /// </summary>
            /// <param name="pageIndex">当前页面码</param>
            /// <param name="pageSize">每页显示行数</param>
            /// <param name="sortFields">排序字段名称</param>
            /// <param name="sortType">排序顺序</param>
            /// <param name="commandType">分页语句类型</param>
            /// <returns></returns>
            public static ChangePage NewInstance(int pageIndex, int pageSize, string sortFields = "", SortType sortType = SortType.DESC, QueryCommandType commandType = QueryCommandType.Text)
            {
                pageIndex = pageIndex <= 0 ? 1 : pageIndex;
                pageSize = pageSize <= 0 ? 10 : pageSize;
                ChangePage changePage = new ChangePage
                {
                    CurrentPageIndex = pageIndex,
                    PageSize = pageSize,
                    SortFields = sortFields,
                    SortType = sortType,
                    CommandType = commandType,
                };
                return changePage;
            }
        }
    }

    现在分页需要的基本参数有了,就是在对数据库操作的时候加入这些参数即可:

     上面是Sqlserver的实现方式,我们再看一下Oracle 的实现方式:

      如果我们想要一页20条数据怎么就和简单了,修改ChangePage的参数就行了。

     由于是MVC,this.ChangePage() 会自动接收参数。

     至于前端,由于我们就用JavaScript去实现了。 这里贴一个Jason写的基于KO写的前端js分页控件:

    function pageModel() {
        this.currentPageIndex = 1;
        this.MaxPageIndex = 1;
        this.loadData = function () { };
        this.pagesize = 10;
        this.eleid = "";
    }
    function koViewModel() {
        var self = this;
        self.Data = [];
    }
    function renderPage(options) {
        var currentPageIndex = options.pageindex;
        var MaxPageIndex = options.MaxPageIndex;
        var loadData = options.loadData;
        var pagesize = options.pagesize || 10;
        var $this = $("#" + options.eleid).parent();
        var ul = $("<ul></ul>").addClass("pagination");
        var prev = $("<li></li>").append($("<a></a>").append($("<i class='icon-double-angle-left'></i>"))).addClass("prev");
        if (currentPageIndex == 1) {
            prev.addClass("disabled");
        }
    
        var next = $("<li></li>").append($("<a></a>").append($("<i class='icon-double-angle-right'></i>"))).addClass("next");
        if (MaxPageIndex <= 1 || currentPageIndex == MaxPageIndex) {
            next.addClass("disabled");
        }
        var recordsinfo = $("<li class='disabled'></li>").append($("<a></a>")
            .append("<span>共</span><span class='totalrecords'>" + options.totalRecords + "</span><span>条,每页</span>" +
            "<span class='pagesize'>" + pagesize + "</span>条,<span></span>" + "<span class='maxpageindex'>" + MaxPageIndex + "</span><span>页</span>"));
     
        var minIndex = currentPageIndex - 5;
        var plus = 0;
        if (minIndex <= 0) {
            plus = 0 - minIndex;
            minIndex = 1;
        }
        var maxIndex = currentPageIndex + 5 + plus;
        if (maxIndex > MaxPageIndex) {
            maxIndex = MaxPageIndex;
        }
        ul.append(prev);
        for (var i = minIndex; i <= maxIndex; i++) {
            var li_html = $("<li></li>");
            if (currentPageIndex == i)
                li_html.addClass("active disabled");
            var item = li_html.append($("<a></a>").html(i));
            ul.append(item);
        }
        ul.append(next);
        ul.append(recordsinfo);
        //ul.append(pagesizeoptions);
        ul.children("li").click(function () {
            if (!$(this).is(".disabled")) {
                var index = 1;
                var pagesize = options.pagesize;
                if ($(this).is(".selectpagesize")) {
                    return;
                } else {
                    index = $(this).text();
                }
                if (index.length == 0) {
                    index = ul.find(".active").text();
                    if ($(this).is(".prev") && index > 1) {
                        index--;
                    } else if ($(this).is(".next") && index < MaxPageIndex) {
                        index++;
                    }
                }
                var arg = $.extend({ "pageindex": parseInt(index), "pagesize": pagesize }, options);
                arg.pageindex = parseInt(index);
                loadData(arg);
            }
        });
        if ($this.parent().find(".dataTables_paginate").length > 0) {
            $this.parent().find(".dataTables_paginate").empty().append(ul);
        } else {
            var div_pagination = $("<div class="dataTables_paginate paging_bootstrap"></div>");
            div_pagination.append(ul);
            $this.after(div_pagination);//.empty().append(ul);
        }
    }
    function renderLoading(eleid) {
        var loadname = eleid + "-loading-" + new Date().valueOf();
        var $this = $("#" + eleid);
        $this.attr("data-loading-id", loadname);
        var count = $("#" + eleid).find("tr").eq(0).find("td,th").length;
        $this.find("tbody").empty();
        var tr = $("<tr></tr>");
        var td = $("<td></td>").attr("colspan", count);
        var wrap = $("<div></div>").addClass("data-loading-wrap text-center");
        var span = $("<span></span>").css({ "border": "1px solid #aaa", "padding": "5px 10px", "line-height": "16px" });
        var img = $("<img />").attr("src", "/assets/images/ko_loading.gif").addClass("icon");
        var tips = $("<span></span>").html("正在加载数据...");
        span.append(img);
        span.append(tips);
        wrap.append(span);
        td.append(wrap);
        tr.append(td);
        if ($this.get(0).tagName != "TABLE") {
            var table = $("<table></table>").attr("id", loadname);
            table.append(tr);
            $this.append(table);
        } else {
            tr.attr("id", loadname);
            $this.append(tr);
        }
    }
    function renderWhenNoData(eleid) {
        var loadname = eleid + "-no-data-" + new Date().valueOf();
        var $this = $("#" + eleid);
        $this.attr("data-nodata-id", loadname);
        var count = $("#" + eleid).find("tr").eq(0).find("td,th").length;
        $this.find("tbody").empty();
        var tr = $("<tr></tr>");
        var td = $("<td></td>").attr("colspan", count);
        var wrap = $("<div></div>").addClass("data-loading-wrap text-center");
        var span = $("<span></span>").css({ "border": "1px solid #aaa", "padding": "5px 10px", "line-height": "16px" });
        //var img = $("<img />").attr("src", "/asserts/images/loading.gif").addClass("icon");
        var tips = $("<span></span>").html("暂无数据");
        //span.append(img);
        span.append(tips);
        wrap.append(span);
        td.append(wrap);
        tr.append(td);
        console.log($this.get(0).tagName);
        if ($this.get(0).tagName != "TABLE") {
            var table = $("<table style='100%;'></table>").attr("id", loadname).addClass("ajax-nodata");
            table.append(tr);
            $this.append(table);
        } else {
            tr.addClass("ajax-nodata").attr("id", loadname);
            $this.append(tr);
        }
    }
    (function ($) {
        $.extend({
            DT: {
                init: function (opt) {
                
                    var container = $("#" + opt.eleid).parent().parent();
                    var activeIndex = container.find(".dataTables_paginate > .pagination > li.active");
                    //console.log(activeIndex);
                    var currentPageIndex = activeIndex.length > 0 ? activeIndex.text() : undefined;
                    if (opt.pageindex) {
    
                    }
                    else if (!opt.pageindex && !currentPageIndex) {
                        opt.pageindex = 1;
                    } else {
                        try {
                            opt.pageindex = parseInt(currentPageIndex);
                        } catch (e) {
                            opt.pageindex = 1;
                        }
                    }
                    if (!opt.pagesize) {
                        opt.pagesize = 10;
                    }
                    this.loadData(opt);
                },
    
                loadData: function (opt) {
                    var pageindex = opt.pageindex || 1;
                    var pagesize = opt.pagesize || 10;
                    var url = opt.url || "";
                    if (typeof(opt.query) == 'string') {
                        var urlquery = opt.query;
                        opt.query = {};
                        var array = urlquery.split('&');
                        for (var i in array) {
                            var keyvalue = array[i].split('=');
                            if (keyvalue[1]) {
                                opt.query[keyvalue[0]] = decodeURI(keyvalue[1]);
                            }
                        }
                    }
                    var query = opt.query || {};
                    var errorfunc = opt.errorfunc || alert;
                    var enablePaginate = opt.enablePaginate;
                    var searchData = query;
                    if (enablePaginate) {
                        searchData = $.extend(query, { "pageindex": pageindex, "pagesize": pagesize });
                    }
                    renderLoading(opt.eleid);
                    var pModel = $.extend(opt, { loadData: this.loadData, MaxPageIndex: 1 });
                    $.ajax({
                        "url": url,
                        "data": searchData,
                        "type": "POST",
                        "success": function (resp) {
                            var viewModel = new koViewModel();
                            if (resp.Success) {
                                var loadingid = $("#" + opt.eleid).attr("data-loading-id");
                                $("#" + loadingid).remove();
                                if (resp.Content && resp.Content.Data && resp.Content.Data.length > 0) {
    
                                    viewModel.Data = resp.Content.Data;
                                    ko.applyBindings(viewModel, document.getElementById(opt.eleid));
                                    if (enablePaginate) {
                                        var maxPageIndex = parseInt(resp.Content.Count / pagesize);
                                        if (resp.Content.Count % pagesize) {
                                            maxPageIndex++;
                                        }
                                        pModel.MaxPageIndex = maxPageIndex;
                                        pModel.totalRecords = resp.Content.Count;
                                        pModel.pagesize = pagesize;
                                        renderPage(pModel);
                                    }
                                } else {
                                    $(".ajax-nodata").remove();
                                    if (opt.renderWhenNoData) {
                                        opt.renderWhenNoData(opt.eleid);
                                    } else {
                                        renderWhenNoData(opt.eleid);
                                    }
                                }
    
                                if (opt.success) {
                                    opt.success.apply(viewModel, [resp]);
                                }
                            } else {
                                var loadingid = $("#" + opt.eleid).attr("data-loading-id");
                                $("#" + loadingid).remove();
                                errorfunc(resp.Message);
                            }
                        },
                        "error": function () {
                            var loadingid = $("#" + opt.eleid).attr("data-loading-id");
                            $("#" + loadingid).remove();
                            errorfunc("连接服务器失败");
                        }
                    })
                }
            }
        });
    })(jQuery);
    
    $(function () {
        $(".ko-pager").each(function (index, item) {
            if ($(item).get(0).tagName.toUpperCase() == "INPUT" || $(item).get(0).tagName.toUpperCase() == "BUTTON") {
                $(item).bind("click", function () {
                    loadDataByKoAttribute(item);
                });
            } else {
                loadDataByKoAttribute(item);
            }
        });
    });
    function loadDataByKoAttribute(item) {
        var elementid = $(item).attr("data-ko-element");
        var url = $(item).attr("data-ko-url");
        var queryinfo = eval("(" + $(item).attr("data-ko-query") + ")");
        var enablePaginate = $(item).attr("data-ko-enablepaginate");
        var pagesize = $(item).attr("data-ko-pagesize") || 10;
        var successName = $(item).attr("data-ko-success");
        var successFunction = function () { };
        if (successName) {
            successFunction = eval(successName);
        }
        var query = {};
        for (var key in queryinfo) {
            if ($(queryinfo[key]).length > 1) {
                var value = "";
                $(queryinfo[key]).each(function (i, ele) {
                    value += $(ele).val();
                    if (i + 1 < $(queryinfo[key]).length) {
                        value += ",";
                    }
                });
                query[key] = value;
            } else {
                query[key] = $(queryinfo[key]).val();
            }
        }
    
        $.DT.init({
            eleid: elementid,
            url: url,
            enablePaginate: enablePaginate == "true" ? true : false,
            pagesize: pagesize,
            query: query,
            success: successFunction
        });
    }

    引用js后,调用即可。

         function init(pageindex) {
                //异步加载列表参数
                var option = {
                    url: '@Url.Action("getusers","user")',//ajax url
                    eleid: 'user-list',//列表的容器ID
                    //pagesize:10,//每页数据条数
                    enablePaginate: true,//是否开启分页
                    //errorfunc:function(str){},//出现错误时的回调
                    //success:function(){},//执行成功的回调
                    //ajax请求时携带的参数,可以使用query:$("#form1").serialize()
                    query: $("#form1").serialize()
                };
                //加载指定页码的数据
                if (pageindex && pageindex > 0) {
                    option.pageindex = pageindex;
                }
                //执行分页列表加载
                $.DT.init(option);
            }

    好吧,本来想一篇博客把主要的三,四个程序集写完。但是看来一篇博客是写不玩了,只能分成三篇来写。因为里面的东西实在太多了,让总结Winner-DA四大点:

    1,多数据的支持;

    2,简洁的分页对象;

    3,封装事务机制;

    4,封装增删查改基本操作;

    今天先写到这里,明天继续写。关于代码的问题,今天没忙过来,这几天我会开一个GitHub,然后把这:

    Winner.Framework.Core      
    Winner.Framework.Encrypt   
    Winner.Framework.Utils        
    Winner.Framework.MVC
     
    这四个主要的程序集给传上去提供给大家下载。关于项目源码在后期随着文章更新,再不断上传源码。关于Winner框架的讨论可以加群:261083244,或者扫描主页左侧二维码加群。
  • 相关阅读:
    [剑指Offer] 59.按之字形顺序打印二叉树
    [剑指Offer] 58.对称的二叉树
    [剑指Offer] 57.二叉树的下一个结点
    [剑指Offer] 56.删除链表中重复的结点
    [剑指Offer] 55.链表中环的入口结点
    [计算机网络] C++模拟telnet登陆SMTP服务发送邮件过程
    [计算机网络-应用层] 因特网中的电子邮件
    [计算机网络-应用层] DNS:因特网的目录服务
    [剑指Offer] 54.字符流中的第一个不重复的字符
    [剑指Offer] 53.表示数值的字符串
  • 原文地址:https://www.cnblogs.com/demon28/p/7943914.html
Copyright © 2011-2022 走看看