C#实现数据更新和删除操作组件

本文讨论数据表记录的更新和删除操作,并实现相关组件,示例以MySQL数据库为主,相关准备知识可以参考作者个人网站资源。

《MySQL数据库应用》合集网址:http://caohuayu.com/article/Group.aspx?id=3

《数据添加、更新和删除》文章网址:http://caohuayu.com/article/Article.aspx?id=a261006

表数据更新组件

首先来看数据更新操作的接口类型,如下面的代码(cfx/data/tUpdate.cs)。

C#
using System.Collections.Generic;

namespace cfx.data
{
    public interface tUpdate
    {
        string CnnStr { get; }
        string Table { get; }
        tUpdate ClearData();
        tUpdate AddData(string name, object value);
        tUpdate AddData(Dictionary<string, object> data);
        tUpdate AddData(tPairList data);
        tUpdate SetCond(tCond cond);
        tUpdate SetCond(string condSql);
        long Update();
    }
    // 其它代码
}

代码中定义了tUpdate接口类型,成员包括:

  • CnnStr只读属性,返回数据库连接字符串。
  • Table只读属性,返回操作的数据表名称。
  • ClearData()方法,清除数据并返回当前实例。
  • AddData()方法,三个重载版本,分别使用“键/值”、字典和tPairList对象添加数据,并返回当前实例。
  • SetCond()方法,两个重载版本,分别使用tCond对象和SQL语句设置更新条件,并返回当前实例。
  • Update()方法,执行更新,并返回影响的记录数,出错时返回小于0的整数。

接下来是更新操作基类的实现,如下面的代码(cfx/data/tUpdate.cs)。

C#
using System.Collections.Generic;

namespace cfx.data
{
    // 其它代码
    public abstract class tUpdateBase : tUpdate
    {
        protected string myCnnStr;
        protected string myTable;
        protected tPairList myData = tPairList.Create();
        protected tCond myCond = null;
        //
        public tUpdateBase(string cnnstr,string table)
        {
            myCnnStr = cnnstr;
            myTable = table;
        }
        //
        public string CnnStr { get { return myCnnStr; } }
        public string Table { get { return myTable; } }
        //
        public tUpdate ClearData()
        {
            myData.Clear();
            return this;
        }
        //
        public tUpdate AddData(string name, object value)
        {
            myData.Add(name, value);
            return this;
        }
        //
        public tUpdate AddData(Dictionary<string, object> data)
        {
            if (data == null) return this;
            foreach(string k in data.Keys){
                myData.Add(k, data[k]);
            }
            return this;
        }
        public tUpdate AddData(tPairList data)
        {
            myData.AddRange(data);
            return this;
        }
        //
        public tUpdate SetCond(tCond cond)
        {
            myCond = cond;
            return this;
        }
        //
        public tUpdate SetCond(string condSql)
        {
            myCond = tCond.Direct(condSql);
            return this;
        }
        //
        public abstract long Update();
    }
}

代码中,tUpdateBase类定义为抽象,并实现tUpdate接口。类中首先定义几个受保护(protected)字段,分别是:

  • myCnnStr,string类型,指定数据库连接字符串,从构造函数带入。
  • myTable,string类型,指定操作数据表名称,从构造函数带入。
  • myData,tPairList类型,指定更新数据,声明时进行了初始化,创建为包含0个元素的tPairList对象。
  • myCond,tCond类型,指定为数据更新条件。

接下来是构造函数,参数需要指定数据库连接字符串和操作数据表名称,并分别保存到myCnnStr和myTable字段。

除了Update()方法,tUpdate接口成员在tUpdateBase类中都已实现,其中,需要更新的数据会添加到myData对象,更新条件会保存到myCond对象。

下面的代码(cfx/data/mysql/tMySqlUpdate.cs),使用tMySqlUpdate类实现MySQL数据库表记录的更新操作。

C#
using System.Collections.Generic;
using System.Text;
using MySql.Data.MySqlClient;

namespace cfx.data.mysql
{
    public class tMySqlUpdate:tUpdateBase
    {
        public tMySqlUpdate(string cnnstr, string table)
            : base(cnnstr, table) { }
        //
        public static tMySqlUpdate Create(string cnnstr,string table)
        {
            return new tMySqlUpdate(cnnstr, table);
        }
        //
        public override long Update()
        {
            try
            {
                List<object> condArg;
                string sql = GetUpdateSql(out condArg);
                if (sql.Length == 0) return -1001;
                using(MySqlConnection cnn  = new MySqlConnection(myCnnStr))
                {
                    cnn.Open();
                    MySqlCommand cmd = cnn.CreateCommand();
                    cmd.CommandText = sql;
                    for (int i = 0; i < myData.Count; i++)
                        cmd.Parameters.AddWithValue("?data" + i, myData[i].Value);
                    for (int i = 0; i < condArg.Count; i++)
                        cmd.Parameters.AddWithValue("?cond" + i, condArg[i]);
                    return cmd.ExecuteNonQueryAsync().Result;
                }
        }
            catch { return -1000; }
        }
        // 生成update语句
        protected string GetUpdateSql(out List<object> condArg)
        {
            string condSql = tMySqlCondBuilder.Get(myCond, out condArg);
            if (condSql.Length == 0) return "";
            //
            if (myCnnStr == null || myCnnStr.Length == 0 ||
                myTable == null || myTable.Length == 0 ||
                myData.Count == 0) return "";
            //
            StringBuilder sb = new StringBuilder(512);
            sb.AppendFormat("update `{0}` set `{1}`=?data0", myTable, myData[0].Name);
            for(int i = 1; i < myData.Count; i++)
            {
                sb.AppendFormat(",`{0}`=?data{1}", myData[i].Name, i);
            }
            sb.Append(" where ");
            sb.Append(condSql);
            return sb.ToString();
        }
        //
    }
}

tMySqlUpdate类继承于tUpdateBase类,构造函数通过基类构造函数实现,需要指定数据库连接字符串和表名;Create()静态方法会返回tMySqlUpdate对象,参数也需要指定数据库连接字符串和表名。

GetUpdateSql()方法用于创建update语句,并通过输出参数condArg带出条件的参数数据。方法中会对更新操作所需的数据进行判断,不满足时返回空字符串,这里不允许无条件更新,当条件语句为空时方法也会返回空字符串。下面是创建update语句的格式:

SQL
update `表名` set `数据字段1`=?data0,`数据字段2`=?data1,`数据字段3`=?data2,...
where <条件>

其中,<条件>语句由tMySqlCondBuilder类生成,所需参数数据由输出参数condArg带出,应注意条件中的参数约定使用?定义,名称为cond加从0开始的序号。

Update()方法中,首先会生成update语句,如果语句为空字符串则返回-1001;接下来会执行更新操作,并返回影响的记录数量。

下面的代码,我们在Program.cs文件中测试tMySqlUpdate类的应用。

C#
using System;
using cfx.data;
using cfx.data.mysql;

namespace csfx_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            string cnnstr = tMySqlHelper.GetCnnStr(
                "127.0.0.1", "cdb_cs1", "root", "DEV_Test123456", 3306);
            //
            long result = tMySqlUpdate.Create(cnnstr, "t1")
                .AddData("f1", "用户1")
                .SetCond(tCond.Equal("f1", "user01"))
                .Update();
            Console.WriteLine(result);
        }
    }
}

成功执行操作后会返回大于等于0的整数,即修改记录的数量。出错时会返回小于0的整数。

表数据删除组件

数据删除操作相对简单,其接口和基类实现如下(cfx/data/tDelete.cs)。

C#
namespace cfx.data
{
    public interface tDelete
    {
        string CnnStr { get; }
        string Table { get; }
        tDelete SetCond(tCond cond);
        tDelete SetCond(string condSql);
        long Delete();
    }
    //
    public abstract class tDeleteBase : tDelete
    {
        protected string myCnnStr;
        protected string myTable;
        protected tCond myCond;
        //
        public tDeleteBase(string cnnstr,string table)
        {
            myCnnStr = cnnstr;
            myTable = table;
        }
        //
        public string CnnStr { get { return myCnnStr; } }
        public string Table { get { return myTable; } }
        public tDelete SetCond(tCond cond)
        {
            myCond = cond;
            return this;
        }
        //
        public tDelete SetCond(string condSql)
        {
            myCond = tCond.Direct(condSql);
            return this;
        }
        //
        public abstract long Delete();
    }
}

tDelete接口中的成员包括:

  • CnnStr只读属性,返回数据库连接字符串,需要构造函数带入。
  • Table只读属性,返回操作的数据表名称,需要构造函数带入。
  • SetCond()方法,两个重载版本,分别使用tCond对象或SQL语句指定条件;方法会返回当前实例。
  • Delete()方法,执行删除操作,并返回删除的记录数量。

tDeletaBase类实现了tDelete接口,其中,首先定义了几个字段:

  • myCnnStr,string类型,保存数据库连接字符串。
  • myTable,string类型,保存删除数据的表名。
  • myCond,tCond类型,保存删除条件。

tDeleteBase()构造函数需要指定数据库连接字符串和表名称,并分别保存到myCnnStr和myTable字段;接下来的SetCond()方法,会将删除条件保存到myCond对象。

下面的代码(cfx/data/mysql/tMySqlDelete.cs),使用tMySqlDelete类实现了MySQL数据库表数据的删除操作。

C#
using System.Collections.Generic;
using System.Text;
using MySql.Data.MySqlClient;

namespace cfx.data.mysql
{
    public class tMySqlDelete : tDeleteBase
    {
        public tMySqlDelete(string cnnstr, string table)
            : base(cnnstr, table) { }
        //
        public static tMySqlDelete Create(string cnnstr,string table)
        {
            return new tMySqlDelete(cnnstr, table);
        }
        //
        public override long Delete()
        {
            try
            {
                List<object> condArg;
                string sql = GetDeleteSql(out condArg);
                if (sql.Length == 0) return -1001;
                using(MySqlConnection cnn = new MySqlConnection(myCnnStr))
                {
                    cnn.Open();
                    MySqlCommand cmd = cnn.CreateCommand();
                    cmd.CommandText = sql;
                    for (int i = 0; i < condArg.Count; i++)
                        cmd.Parameters.AddWithValue("?cond" + i, condArg[i]);
                    return cmd.ExecuteNonQueryAsync().Result;
                }
            }
            catch { return -1000; }
        }
        //
        protected string GetDeleteSql(out List<object> condArg)
        {
            string condSql = tMySqlCondBuilder.Get(myCond, out condArg);
            if (condSql.Length==0) return "";
            //
            if (myCnnStr == null || myCnnStr.Length == 0 ||
                myTable == null || myTable.Length == 0) return "";
            //
            StringBuilder sb = new StringBuilder(256);
            sb.AppendFormat("delete from `{0}` where {1}", myTable, condSql);
            return sb.ToString();
        }
        //
    }
}

代码中,构造函数和Create()静态方法用于创建tMySqlDelete类的实例,参数需要数据库连接字符串和表名。

GetDeleteSql()方法用于生成delete语句,这里同样不允许无条件删除操作;当条件或其它操作要素不满足时会返回空字符串。

Delete()方法会执行删除操作,并返回删除的记录数量。出错时会返回小于0的整数。

下面的代码,在Program.cs文件中测试tMySqlDelete类的应用。

C#
using System;
using cfx.data;
using cfx.data.mysql;

namespace csfx_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            string cnnstr = tMySqlHelper.GetCnnStr(
                "127.0.0.1", "cdb_cs1", "root", "DEV_Test123456", 3306);
            //
            long result = tMySqlDelete.Create(cnnstr, "t1")
                .SetCond(tCond.Equal("f1", "用户1"))
                .Delete();
            Console.WriteLine(result);
        }
    }
}

执行代码会删除t1表中f1字段等于“用户1”的记录,正确执行会显示删除的记录数量,应该是大于或等于0的整数(删除的记录数量),执行错误时会返回小于0的整数。

SQL Server数据更新和删除类

首先是SQL Server数据库表数据更新操作,使用tSqlUpdate类实现,如下面的代码(cfx/data/sql/tSqlUpdate.cs)。

C#
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace cfx.data.sql
{
    public class tSqlUpdate:tUpdateBase
    {
        public tSqlUpdate(string cnnstr, string table)
            : base(cnnstr, table) { }
        //
        public static tSqlUpdate Create(string cnnstr,string table)
        {
            return new tSqlUpdate(cnnstr, table);
        }
        //
        public override long Update()
        {
            try
            {
                List<object> condArg;
                string sql = GetUpdateSql(out condArg);
                if (sql.Length == 0) return -1001;
                using(SqlConnection cnn  = new SqlConnection(myCnnStr))
                {
                    cnn.Open();
                    SqlCommand cmd = cnn.CreateCommand();
                    cmd.CommandText = sql;
                    for (int i = 0; i < myData.Count; i++)
                        cmd.Parameters.AddWithValue("@data" + i, myData[i].Value);
                    for (int i = 0; i < condArg.Count; i++)
                        cmd.Parameters.AddWithValue("@cond" + i, condArg[i]);
                    return cmd.ExecuteNonQueryAsync().Result;
                }
        }
            catch { return -1000; }
        }
        // 生成update语句
        protected string GetUpdateSql(out List<object> condArg)
        {
            string condSql = tSqlCondBuilder.Get(myCond, out condArg);
            if (condSql.Length == 0) return "";
            //
            if (myCnnStr == null || myCnnStr.Length == 0 ||
                myTable == null || myTable.Length == 0 ||
                myData.Count == 0) return "";
            //
            StringBuilder sb = new StringBuilder(512);
            sb.AppendFormat("update [{0}] set [{1}]=@data0", myTable, myData[0].Name);
            for(int i = 1; i < myData.Count; i++)
            {
                sb.AppendFormat(",[{0}]=@data{1}", myData[i].Name, i);
            }
            sb.Append(" where ");
            sb.Append(condSql);
            return sb.ToString();
        }
        //
    }
}

下面的代码(cfx/data/sql/tSqlDelete.cs)是SQL Server数据库表数据删除操作,使用tSqlDelete类实现。

C#
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace cfx.data.sql
{
    public class tSqlDelete : tDeleteBase
    {
        public tSqlDelete(string cnnstr, string table)
            : base(cnnstr, table) { }
        //
        public static tSqlDelete Create(string cnnstr,string table)
        {
            return new tSqlDelete(cnnstr, table);
        }
        //
        public override long Delete()
        {
            try
            {
                List<object> condArg;
                string sql = GetDeleteSql(out condArg);
                if (sql.Length == 0) return -1001;
                using(SqlConnection cnn = new SqlConnection(myCnnStr))
                {
                    cnn.Open();
                    SqlCommand cmd = cnn.CreateCommand();
                    cmd.CommandText = sql;
                    for (int i = 0; i < condArg.Count; i++)
                        cmd.Parameters.AddWithValue("@cond" + i, condArg[i]);
                    return cmd.ExecuteNonQueryAsync().Result;
                }
            }
            catch { return -1000; }
        }
        //
        protected string GetDeleteSql(out List<object> condArg)
        {
            string condSql = tSqlCondBuilder.Get(myCond, out condArg);
            if (condSql.Length==0) return "";
            //
            if (myCnnStr == null || myCnnStr.Length == 0 ||
                myTable == null || myTable.Length == 0) return "";
            //
            StringBuilder sb = new StringBuilder(256);
            sb.AppendFormat("delete from [{0}] where {1}", myTable, condSql);
            return sb.ToString();
        }
        //
    }
}

tSqlUpdate和tSqlDelete类中,SQL Server数据库对象名称使用一对方括号定义,参数使用@符号定义,并使用了cfx.data.sql命名空间和System.Data.SqlClient命名空间的资源,这里不再详细说明。