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,或者扫描主页左侧二维码加群。
  • 相关阅读:
    1026 Table Tennis (30)
    1029 Median
    1025 PAT Ranking (25)
    1017 Queueing at Bank (25)
    1014 Waiting in Line (30)
    1057 Stack (30)
    1010 Radix (25)
    1008 Elevator (20)
    字母大小写转换
    Nmap的基础知识
  • 原文地址:https://www.cnblogs.com/demon28/p/7943914.html
Copyright © 2011-2022 走看看