Commit efa08ef5 authored by 罗显健's avatar 罗显健

数据访问测试类项目

parent c76caf61
......@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools", "Tools\Tools.csproj
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ftt.PatchPack", "Ftt.PatchPack\Ftt.PatchPack.csproj", "{42E384C1-CC13-494D-90E2-33C399E13F07}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{1447F8DF-E552-40DD-8F02-B55D75FBC77A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......@@ -55,6 +57,18 @@ Global
{42E384C1-CC13-494D-90E2-33C399E13F07}.Release|x64.Build.0 = Release|Any CPU
{42E384C1-CC13-494D-90E2-33C399E13F07}.Release|x86.ActiveCfg = Release|Any CPU
{42E384C1-CC13-494D-90E2-33C399E13F07}.Release|x86.Build.0 = Release|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Debug|x64.ActiveCfg = Debug|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Debug|x64.Build.0 = Debug|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Debug|x86.ActiveCfg = Debug|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Debug|x86.Build.0 = Debug|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Release|Any CPU.Build.0 = Release|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Release|x64.ActiveCfg = Release|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Release|x64.Build.0 = Release|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Release|x86.ActiveCfg = Release|Any CPU
{1447F8DF-E552-40DD-8F02-B55D75FBC77A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
</configuration>
using Dapper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test.DBO
{
/// <summary>
/// Dapper Dbo.
/// 更换不同数据库,只需修改 NewConn <see cref="NewConn"/> 以及少量代码 <see cref="GetDataSet"/> <see cref="GetDataTable"/>
/// </summary>
public class DbDapper : IDisposable
{
public static bool DEBUG_MODE = false;
private readonly string connectionString;
private System.Data.IDbConnection conn;
/// <summary>
/// 平台用、企业相关操作禁止使用。
/// </summary>
/// <param name="dbConnectionString"></param>
public DbDapper(string dbConnectionString)
{
connectionString = dbConnectionString;
}
public IDbConnection NewConn()
{
// return new NpgsqlConnection(connectionString);
return new SqlConnection(connectionString);
}
/// <summary>
/// 在委托里执行一堆事务
/// 委托成功执行会自动提交事件,失败会自动回滚.
/// 注意:不要在这个委托里调用 带 Async的异步方法,可能会造成问题:BeginExecuteNonQuery requires an open and available Connection. The connection's current state is open
/// </summary>
/// <param name="action"></param>
public void Trans(Action<IDbConnection, IDbTransaction> action)
{
using (var conn = NewConn())
{
conn.Open();
using (var trans = conn.BeginTransaction())
{
try
{
action(conn, trans);
trans.Commit();
}
catch (Exception)
{
trans.Rollback();
throw;
}
}
conn.Close();
}
}
public T ExecuteScalar<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return conn.ExecuteScalar<T>(commandText, paras, commandType: CommandType.Text);
}
}
public async Task<T> ExecuteScalarAsync<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return await conn.ExecuteScalarAsync<T>(commandText, paras, commandType: CommandType.Text);
}
}
public async Task<T> QueryFirstAsync<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return await conn.QueryFirstAsync<T>(commandText, paras, commandType: CommandType.Text);
}
}
public T QueryFirst<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return conn.QueryFirst<T>(commandText, paras, commandType: CommandType.Text);
}
}
public T QueryFirstOrDefault<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return conn.QueryFirstOrDefault<T>(commandText, paras, commandType: CommandType.Text);
}
}
public async Task<T> QueryFirstOrDefaultAsync<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return await conn.QueryFirstOrDefaultAsync<T>(commandText, paras, commandType: CommandType.Text);
}
}
public void Execute(string commandText, object paras = null)
{
using (var conn = NewConn())
{
conn.Execute(commandText, paras, commandType: CommandType.Text);
}
}
public async Task<int> ExecuteAsync(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return await conn.ExecuteAsync(commandText, paras, commandType: CommandType.Text);
}
}
public async Task ExecuteAsyncByProc(string procName, object paras = null)
{
using (var conn = NewConn())
{
await conn.ExecuteAsync(procName, paras, commandType: CommandType.StoredProcedure);
}
}
public async Task<IEnumerable<T>> QueryAsync<T>(string commandText, object paras = null, CommandType commandType = CommandType.Text)
{
using (var conn = NewConn())
{
return await conn.QueryAsync<T>(commandText, paras, commandType: commandType);
}
}
public IEnumerable<T> Query<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return conn.Query<T>(commandText, paras, commandType: CommandType.Text);
}
}
public T ExecuteScalarByProc<T>(string procName, object paras = null)
{
using (var conn = NewConn())
{
return conn.ExecuteScalar<T>(procName, paras, commandType: CommandType.StoredProcedure);
}
}
public Task<T> QueryFirstAsyncByProc<T>(string procName, object paras = null)
{
using (var conn = NewConn())
{
return conn.QueryFirstAsync<T>(procName, paras, commandType: CommandType.StoredProcedure);
}
}
public Task ExecuteAsync<T>(string sql, object p)
{
throw new NotImplementedException();
}
public Task<IEnumerable<T>> QueryAsyncByProc<T>(string commandText, object paras = null)
{
using (var conn = NewConn())
{
return conn.QueryAsync<T>(commandText, paras, commandType: CommandType.StoredProcedure);
}
}
#region DataTable、DataSet
public DataTable GetTable(string commandText, object paras = null)
{
using (var conn = NewConn())
{
conn.Open();
using (var reader = conn.ExecuteReader(commandText, paras))
{
var dt = new DataTable();
while (reader.Read())
{
if (dt.Columns.Count == 0)
{
for (var i = 0; i < reader.FieldCount; i++)
{
dt.Columns.Add(reader.GetName(i), reader.GetFieldType(i));
}
}
var row = dt.Rows.Add();
for (var i = 0; i < reader.FieldCount; i++)
{
row[i] = reader.GetValue(i);
}
}
return dt;
}
}
}
public DataSet GetDataSet(string sql, object paras = null, bool isSp = false)
{
using (var conn = NewConn())
{
var ds = new DataSet();
using (var cmd = new SqlCommand(sql, (SqlConnection)conn))
{
if (isSp)
cmd.CommandType = CommandType.StoredProcedure;
if (paras != null)
{
var properties = paras.GetType().GetProperties();
foreach (var property in properties)
{
cmd.Parameters.AddWithValue("@" + property.Name, property.GetValue(paras, null));
}
}
using (var da = new SqlDataAdapter(cmd))
{
da.Fill(ds);
}
}
return ds;
}
}
/// <summary>
///
/// </summary>
/// <param name="sql"></param>
/// <param name="paras"></param>
/// <param name="isSp"></param>
/// <returns></returns>
public DataTable GetDataTable(string sql, object paras = null, bool isSp = false)
{
using (var conn = NewConn())
{
var dt = new DataTable();
using (var cmd = new SqlCommand(sql, (SqlConnection)conn))
{
if (isSp)
cmd.CommandType = CommandType.StoredProcedure;
if (paras != null)
{
var properties = paras.GetType().GetProperties();
foreach (var property in properties)
{
cmd.Parameters.AddWithValue("@" + property.Name, property.GetValue(paras, null));
}
}
using (var da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
}
return dt;
}
}
#endregion
public void Dispose()
{
if (conn != null)
{
try
{
conn.Dispose();
}
catch
{
}
conn = null;
}
}
}
}

using FluentData;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using test.Extension;
namespace test.DBO
{
/// <summary>
/// 数据库操作类
/// 更换不同数据库,只需修改 NewConn <see cref="NewConn"/> 以及少量代码 <see cref="GetDataSet"/> <see cref="GetDataTable"/>
/// </summary>
public class DbFluentData
{
private string connectionString;
private readonly SqlServerProvider providerMssql = new SqlServerProvider();
public DbFluentData(string conn)
{
connectionString = conn;
}
public IDbContext NewContext()
{
return new DbContext().ConnectionString(connectionString, new SqlServerProvider(), (string)null);
}
#region Insert
/// <summary>
/// 插入元素
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="model"></param>
public void Insert<T>(T model)
{
using (IDbContext context = this.NewContext())
{
context.Insert<T>(typeof(T).Name, model).AutoMap(new Expression<Func<T, object>>[0]).Execute();
}
}
/// <summary>
/// 插入元素,并返回自增长的值.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="model"></param>
/// <param name="keyExpression"></param>
/// <returns></returns>
public TKey Insert<T, TKey>(T model, Expression<Func<T, object>> keyExpression)
{
TKey result;
using (IDbContext context = this.NewContext())
{
result = context.Insert<T>(typeof(T).Name, model).AutoMap(new Expression<Func<T, object>>[]
{
keyExpression
}).ExecuteReturnLastId<TKey>(null);
}
return result;
}
public void Insert<T>(T model, params Expression<Func<T, object>>[] ignoreProperties)
{
using (IDbContext context = this.NewContext())
{
context.Insert<T>(typeof(T).Name, model).AutoMap(ignoreProperties).Execute();
}
}
/// <summary>
/// 往数据库里插入一个字典
/// </summary>
/// <param name="tableName"></param>
/// <param name="dict"></param>
public void Insert(string tableName, Dictionary<string, object> dict)
{
StringBuilder sb = new StringBuilder();
sb.Append(" INSERT INTO ");
sb.Append(tableName);
sb.Append(" ( ");
int i = 0;
foreach (KeyValuePair<string, object> o in dict)
{
if (i > 0)
{
sb.Append(",");
}
i++;
sb.Append(o.Key);
}
sb.Append(") values (");
i = 0;
foreach (KeyValuePair<string, object> o2 in dict)
{
if (i > 0)
{
sb.Append(",");
}
i++;
sb.Append("@").Append(o2.Key);
}
sb.Append(")");
using (IDbContext context = this.NewContext())
{
IDbCommand query = context.Sql(sb.ToString(), new object[0]);
foreach (KeyValuePair<string, object> o3 in dict)
{
query.Parameter(o3.Key, o3.Value, DataTypes.Object, ParameterDirection.Input, 0);
}
query.Execute();
}
}
/// <summary>
/// 往数据库里插入一下字典,并返回自增长键的值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tableName"></param>
/// <param name="dict"></param>
/// <returns></returns>
public T InsertAndReturnLastId<T>(string tableName, Dictionary<string, object> dict)
{
StringBuilder sb = new StringBuilder();
sb.Append(" INSERT INTO ");
sb.Append(tableName);
sb.Append(" ( ");
int i = 0;
foreach (KeyValuePair<string, object> o in dict)
{
if (i > 0)
{
sb.Append(",");
}
i++;
sb.Append(o.Key);
}
sb.Append(") values (");
i = 0;
foreach (KeyValuePair<string, object> o2 in dict)
{
if (i > 0)
{
sb.Append(",");
}
i++;
sb.Append("@").Append(o2.Key);
}
sb.Append(")");
T result;
using (IDbContext context = this.NewContext())
{
IDbCommand query = context.Sql(sb.ToString(), new object[0]);
foreach (KeyValuePair<string, object> o3 in dict)
{
query.Parameter(o3.Key, o3.Value, DataTypes.Object, ParameterDirection.Input, 0);
}
result = query.ExecuteReturnLastId<T>(null);
}
return result;
}
#endregion
#region Delete
public void DeleteAll<T>()
{
using (IDbContext ctx = this.NewContext())
{
ctx.Sql("delete from " + typeof(T).Name, new object[0]).Execute();
}
}
public void Delete<T>(string keyField, object value)
{
using (IDbContext ctx = this.NewContext())
{
ctx.Sql(string.Format("delete from {0} where {1}=@id", typeof(T).Name, keyField), new object[0]).Parameter("id", value, DataTypes.Object, ParameterDirection.Input, 0).Execute();
}
}
public void Delete<T>(Expression<Func<T, bool>> where)
{
using (IDbContext ctx = this.NewContext())
{
ExpressionExtension.BinaryExpressionInfo bi = where.GetBinaryExpressionInfo();
string keyField = bi.LeftName;
object value = bi.GetRightValue();
ctx.Sql(string.Format("delete from {0} where {1}=@id", typeof(T).Name, keyField), new object[0]).Parameter("id", value, DataTypes.Object, ParameterDirection.Input, 0).Execute();
}
}
#endregion
#region Update
/// <summary>
/// 数据字典内容,更新数据
/// </summary>
/// <param name="tableName"></param>
/// <param name="where"></param>
/// <param name="dict"></param>
public void Update(string tableName, string where, Dictionary<string, object> dict)
{
StringBuilder sb = new StringBuilder();
sb.Append(" UPDATE ");
sb.Append(tableName);
sb.Append(" SET ");
int i = 0;
foreach (KeyValuePair<string, object> o in dict)
{
if (i > 0)
{
sb.Append(",");
}
i++;
sb.Append(o.Key).Append("=@").Append(o.Key);
}
if (!string.IsNullOrEmpty(where))
{
sb.Append(" WHERE ").Append(where);
}
using (IDbContext context = this.NewContext())
{
IDbCommand query = context.Sql(sb.ToString(), new object[0]);
foreach (KeyValuePair<string, object> o2 in dict)
{
query.Parameter(o2.Key, o2.Value, DataTypes.Object, ParameterDirection.Input, 0);
}
query.Execute();
}
}
public void Update(string sql, Dictionary<string, object> dict)
{
using (IDbContext context = this.NewContext())
{
IDbCommand query = context.Sql(sql, new object[0]);
foreach (KeyValuePair<string, object> o2 in dict)
{
query.Parameter(o2.Key, o2.Value, DataTypes.Object, ParameterDirection.Input, 0);
}
query.Execute();
}
}
public void Update<T>(T model, Expression<Func<T, object>> where, params Expression<Func<T, object>>[] ignoreProperties)
{
using (IDbContext context = this.NewContext())
{
context.Update<T>(typeof(T).Name, model).AutoMap(new Expression<Func<T, object>>[]
{
where
}).Where(where, DataTypes.Object, 0).Execute();
}
}
#endregion
#region Select
public T SelectOne<T>(Expression<Func<T, bool>> where)
{
T result;
using (IDbContext ctx = this.NewContext())
{
ExpressionExtension.BinaryExpressionInfo bi = where.GetBinaryExpressionInfo();
string keyField = bi.LeftName;
object value = bi.GetRightValue();
result = ctx.Sql(string.Format("select * from {0} where {1}=@id", typeof(T).Name, keyField), new object[0]).Parameter("id", value, DataTypes.Object, ParameterDirection.Input, 0).QuerySingle<T>(null);
}
return result;
}
public List<T> SelectAll<T>()
{
List<T> result;
using (IDbContext context = this.NewContext())
{
result = context.SelectAll<T>();
}
return result;
}
public List<T> SelectAll<T>(params string[] fields)
{
if (fields == null || fields.Length == 0)
{
throw new ArgumentNullException("fields");
}
string fieldsString = fields.JoinString(",");
List<T> result;
using (IDbContext ctx = this.NewContext())
{
result = ctx.Sql(string.Format("select {0} from {1}", fieldsString, typeof(T).Name), new object[0]).QueryMany<T>(null);
}
return result;
}
/// <summary>
/// 执行一个SQL,返回多行
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql"></param>
/// <param name="paras"></param>
/// <returns></returns>
public List<T> SelectMany<T>(string sql, params FluentDbParameter[] paras)
{
List<T> result;
using (IDbContext ctx = this.NewContext())
{
FluentData.IDbCommand query = ctx.Sql(sql, new object[0]);
if (paras != null)
{
for (int i = 0; i < paras.Length; i++)
{
FluentDbParameter para = paras[i];
query.Parameter(para.Key, para.Value, DataTypes.Object, FluentData.ParameterDirection.Input, 0);
}
}
result = query.QueryMany<T>(null);
}
return result;
}
#endregion
#region Exec
/// <summary>
/// 执行一个SQL,没有返回任何数据.
/// </summary>
/// <param name="sql"></param>
/// <param name="parameters"></param>
public void ExecuteNoQuery(string sql, params object[] parameters)
{
using (IDbContext context = this.NewContext())
{
context.Sql(sql, parameters).Execute();
}
}
public void Execute(string sql, Dictionary<string, object> dict)
{
using (IDbContext context = this.NewContext())
{
IDbCommand query = context.Sql(sql, new object[0]);
foreach (KeyValuePair<string, object> o2 in dict)
{
query.Parameter(o2.Key, o2.Value, DataTypes.Object, ParameterDirection.Input, 0);
}
query.Execute();
}
}
public void Execute(string sql, IEnumerable<Dictionary<string, object>> keyValuePairs)
{
using (IDbContext context = this.NewContext().UseTransaction(true))
{
foreach (var dict in keyValuePairs)
{
IDbCommand query = context.Sql(sql, new object[0]);
foreach (KeyValuePair<string, object> o2 in dict)
{
query.Parameter(o2.Key, o2.Value, DataTypes.Object, ParameterDirection.Input, 0);
}
query.Execute();
}
}
}
#endregion
}
public static class IDbContextExtension
{
/// <summary>
/// 自动编辑 select count 语句,并返回结果
/// </summary>
/// <param name="db"></param>
/// <param name="tableName"></param>
/// <param name="whereCondtion">WHERE后面的语句,各参数以p开头,0开始的命名规则.例 " UserID=@p0 and Password=@p1"</param>
/// <param name="paras"></param>
/// <returns></returns>
public static int Count(this IDbContext db, string tableName, string whereCondtion = null, params object[] paras)
{
StringBuilder sql = new StringBuilder();
sql.Append("select count(*) from ").Append(tableName);
if (whereCondtion != null)
{
sql.Append(" WHERE ").Append(whereCondtion);
}
IDbCommand cmd = db.Sql(sql.ToString(), new object[0]);
if (paras != null)
{
for (int i = 0; i < paras.Length; i++)
{
cmd = cmd.Parameter("p" + i, paras[i], DataTypes.Object, ParameterDirection.Input, 0);
}
}
return cmd.QuerySingle<int>(null);
}
public static SelectOneBuilder<T> SelectOne<T>(this IDbContext context)
{
return new SelectOneBuilder<T>(context);
}
/// <summary>
/// 根据条件,求符合条件的记录是否存在.类似本类中的 Count扩展方法
/// </summary>
/// <param name="db"></param>
/// <param name="tableName"></param>
/// <param name="whereCondtion"></param>
/// <param name="paras"></param>
/// <returns></returns>
public static bool Exists(this IDbContext db, string tableName, string whereCondtion = null, params object[] paras)
{
StringBuilder sql = new StringBuilder();
sql.Append("if exists (select * from ").Append(tableName);
if (whereCondtion != null)
{
sql.Append(" WHERE ").Append(whereCondtion);
}
sql.Append(" ) select 1 else select 0");
IDbCommand cmd = db.Sql(sql.ToString(), new object[0]);
if (paras != null)
{
for (int i = 0; i < paras.Length; i++)
{
cmd = cmd.Parameter("p" + i, paras[i], DataTypes.Object, ParameterDirection.Input, 0);
}
}
return cmd.QuerySingle<int>(null) > 0;
}
public static List<T> SelectAll<T>(this IDbContext db)
{
return db.Sql("select * from " + typeof(T).Name, new object[0]).QueryMany<T>(null);
}
}
public class SelectOneBuilder<T>
{
private readonly IDbContext context;
private readonly StringBuilder sb = new StringBuilder();
private readonly Dictionary<string, object> parameters = new Dictionary<string, object>();
public SelectOneBuilder(IDbContext context)
{
this.context = context;
this.sb.Append("SELECT * FROM ").Append(typeof(T).Name).Append(" WHERE 1=1 ");
}
public SelectOneBuilder<T> Where(string columnName, object value)
{
this.sb.Append(" AND ").Append(columnName).Append(" = @").Append(columnName);
this.parameters[columnName] = value;
return this;
}
public SelectOneBuilder<T> Where(Expression<Func<T, bool>> exp)
{
ExpressionExtension.BinaryExpressionInfo expInfo = exp.GetBinaryExpressionInfo();
string columnName = expInfo.LeftName;
object value = expInfo.GetRightValue();
this.sb.Append(" AND ");
ExpressionType nodeType = expInfo.Body.NodeType;
switch (nodeType)
{
case ExpressionType.Equal:
this.sb.AppendFormat("{0} = @{0}", columnName);
goto IL_E5;
case ExpressionType.ExclusiveOr:
case ExpressionType.Invoke:
case ExpressionType.Lambda:
case ExpressionType.LeftShift:
break;
case ExpressionType.GreaterThan:
this.sb.AppendFormat("{0} > @{0}", columnName);
goto IL_E5;
case ExpressionType.GreaterThanOrEqual:
this.sb.AppendFormat("{0} >= @{0}", columnName);
goto IL_E5;
case ExpressionType.LessThan:
this.sb.AppendFormat("{0} < @{0}", columnName);
goto IL_E5;
case ExpressionType.LessThanOrEqual:
this.sb.AppendFormat("{0} <= @{0}", columnName);
goto IL_E5;
default:
if (nodeType == ExpressionType.NotEqual)
{
this.sb.AppendFormat("{0} != @{0}", columnName);
goto IL_E5;
}
break;
}
throw new NotImplementedException();
IL_E5:
this.parameters[columnName] = value;
return this;
}
public T Execute()
{
string sql = this.sb.ToString();
IDbCommand cmd = this.context.Sql(sql, new object[0]);
foreach (KeyValuePair<string, object> p in this.parameters)
{
cmd.Parameter(p.Key, p.Value, DataTypes.Object, ParameterDirection.Input, 0);
}
return cmd.QuerySingle<T>(null);
}
}
public struct FluentDbParameter
{
public string Key;
public object Value;
public FluentDbParameter(string k, object v)
{
this.Key = k;
this.Value = v;
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace test.DBO
{
/// <summary>
/// The SqlHelper class is intended to encapsulate high performance, scalable best practices for
/// common uses of SqlClient.
/// </summary>
public sealed class DbSqlHelper
{
#region private utility methods & constructors
private const int TIMEOUT = 1000 * 60 * 10; //表示无限制等待。
//Since this class provides only static methods, make the default constructor private to prevent
//instances from being created with "new SqlHelper()".
private DbSqlHelper() { }
/// <summary>
/// This method is used to attach array of SqlParameters to a SqlCommand.
///
/// This method will assign a value of DbNull to any parameter with a direction of
/// InputOutput and a value of null.
///
/// This behavior will prevent default values from being used, but
/// this will be the less common case than an intended pure output parameter (derived as InputOutput)
/// where the user provided no input value.
/// </summary>
/// <param name="command">The command to which the parameters will be added</param>
/// <param name="commandParameters">an array of SqlParameters tho be added to command</param>
private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
{
foreach (SqlParameter p in commandParameters)
{
//check for derived output value with no value assigned
if ((p.Direction == ParameterDirection.InputOutput) && (p.Value == null))
{
p.Value = DBNull.Value;
}
command.Parameters.Add(p);
}
}
/// <summary>
/// This method assigns an array of values to an array of SqlParameters.
/// </summary>
/// <param name="commandParameters">array of SqlParameters to be assigned values</param>
/// <param name="parameterValues">array of objects holding the values to be assigned</param>
private static void AssignParameterValues(SqlParameter[] commandParameters, object[] parameterValues)
{
if ((commandParameters == null) || (parameterValues == null))
{
//do nothing if we get no data
return;
}
// we must have the same number of values as we pave parameters to put them in
if (commandParameters.Length != parameterValues.Length)
{
throw new ArgumentException("Parameter count does not match Parameter Value count.");
}
//iterate through the SqlParameters, assigning the values from the corresponding position in the
//value array
for (int i = 0, j = commandParameters.Length; i < j; i++)
{
commandParameters[i].Value = parameterValues[i];
}
}
/// <summary>
/// This method opens (if necessary) and assigns a connection, transaction, command type and parameters
/// to the provided command.
/// </summary>
/// <param name="command">the SqlCommand to be prepared</param>
/// <param name="connection">a valid SqlConnection, on which to execute this command</param>
/// <param name="transaction">a valid SqlTransaction, or 'null'</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParameters to be associated with the command or 'null' if no parameters are required</param>
private static void PrepareCommand(SqlCommand command, SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters)
{
//if the provided connection is not open, we will open it
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
//associate the connection with the command
command.Connection = connection;
//set the command text (stored procedure name or SQL statement)
command.CommandText = commandText;
//if we were provided a transaction, assign it.
if (transaction != null)
{
command.Transaction = transaction;
}
//set the command type
command.CommandType = commandType;
//attach the command parameters if they are provided
if (commandParameters != null)
{
AttachParameters(command, commandParameters);
}
return;
}
#endregion private utility methods & constructors
/// <summary>
/// 获取数据连接字符窜。
/// </summary>
/// <returns></returns>
#region ExecuteNonQuery
/// <summary>
/// Execute a SqlCommand (that returns no resultset and takes no parameters) against the database specified in
/// the connection string.
/// </summary>
/// <remarks>
/// e.g.:
/// int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders");
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteNonQuery(connectionString, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns no resultset) against the database specified in the connection string
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// int result = ExecuteNonQuery(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create & open a SqlConnection, and dispose of it after we are done.
using (SqlConnection cn = new SqlConnection(connectionString))
{
cn.Open();
//call the overload that takes a connection in place of the connection string
return ExecuteNonQuery(cn, commandType, commandText, commandParameters);
}
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns no resultset) against the database specified in
/// the connection string using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// int result = ExecuteNonQuery(connString, "PublishOrders", 24, 36);
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="spName">the name of the stored prcedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(string connectionString, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns no resultset and takes no parameters) against the provided SqlConnection.
/// </summary>
/// <remarks>
/// e.g.:
/// int result = ExecuteNonQuery(conn, CommandType.StoredProcedure, "PublishOrders");
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteNonQuery(connection, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns no resultset) against the specified SqlConnection
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// int result = ExecuteNonQuery(conn, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
cmd.CommandTimeout = TIMEOUT; //add by steven
PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
//finally, execute the command.
int retval = cmd.ExecuteNonQuery();
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
return retval;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified SqlConnection
/// using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// int result = ExecuteNonQuery(conn, "PublishOrders", 24, 36);
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(SqlConnection connection, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns no resultset and takes no parameters) against the provided SqlTransaction.
/// </summary>
/// <remarks>
/// e.g.:
/// int result = ExecuteNonQuery(trans, CommandType.StoredProcedure, "PublishOrders");
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(SqlTransaction transaction, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteNonQuery(transaction, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns no resultset) against the specified SqlTransaction
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// int result = ExecuteNonQuery(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
cmd.CommandTimeout = TIMEOUT; //add by steven
PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
//finally, execute the command.
int retval = cmd.ExecuteNonQuery();
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
return retval;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified
/// SqlTransaction using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// int result = ExecuteNonQuery(conn, trans, "PublishOrders", 24, 36);
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>an int representing the number of rows affected by the command</returns>
public static int ExecuteNonQuery(SqlTransaction transaction, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName);
}
}
#endregion ExecuteNonQuery
#region ExecuteDataSet
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the database specified in
/// the connection string.
/// </summary>
/// <remarks>
/// e.g.:
/// DataSet ds = ExecuteDataset(connString, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteDataset(connectionString, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// DataSet ds = ExecuteDataset(connString, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create & open a SqlConnection, and dispose of it after we are done.
using (SqlConnection cn = new SqlConnection(connectionString))
{
cn.Open();
//call the overload that takes a connection in place of the connection string
return ExecuteDataset(cn, commandType, commandText, commandParameters);
}
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in
/// the connection string using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// DataSet ds = ExecuteDataset(connString, "GetOrders", 24, 36);
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(string connectionString, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection.
/// </summary>
/// <remarks>
/// e.g.:
/// DataSet ds = ExecuteDataset(conn, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(SqlConnection connection, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteDataset(connection, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// DataSet ds = ExecuteDataset(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
//create the DataAdapter & DataSet
SqlDataAdapter da = new SqlDataAdapter(cmd);
//让命令一直执行,直到用户取消它
da.SelectCommand.CommandTimeout = TIMEOUT;
DataSet ds = new DataSet();
//fill the DataSet using default values for DataTable names, etc.
da.Fill(ds);
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
//return the dataset
return ds;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection
/// using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// DataSet ds = ExecuteDataset(conn, "GetOrders", 24, 36);
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(SqlConnection connection, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteDataset(connection, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction.
/// </summary>
/// <remarks>
/// e.g.:
/// DataSet ds = ExecuteDataset(trans, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(SqlTransaction transaction, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteDataset(transaction, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// DataSet ds = ExecuteDataset(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
//create the DataAdapter & DataSet
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
//fill the DataSet using default values for DataTable names, etc.
da.Fill(ds);
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
//return the dataset
return ds;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified
/// SqlTransaction using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// DataSet ds = ExecuteDataset(trans, "GetOrders", 24, 36);
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static DataSet ExecuteDataset(SqlTransaction transaction, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteDataset(transaction, CommandType.StoredProcedure, spName);
}
}
#endregion ExecuteDataSet
#region ExecuteReader
/// <summary>
/// this enum is used to indicate whether the connection was provided by the caller, or created by SqlHelper, so that
/// we can set the appropriate CommandBehavior when calling ExecuteReader()
/// </summary>
private enum SqlConnectionOwnership
{
/// <summary>Connection is owned and managed by SqlHelper</summary>
Internal,
/// <summary>Connection is owned and managed by the caller</summary>
External
}
/// <summary>
/// Create and prepare a SqlCommand, and call ExecuteReader with the appropriate CommandBehavior.
/// </summary>
/// <remarks>
/// If we created and opened the connection, we want the connection to be closed when the DataReader is closed.
///
/// If the caller provided the connection, we want to leave it to them to manage.
/// </remarks>
/// <param name="connection">a valid SqlConnection, on which to execute this command</param>
/// <param name="transaction">a valid SqlTransaction, or 'null'</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParameters to be associated with the command or 'null' if no parameters are required</param>
/// <param name="connectionOwnership">indicates whether the connection parameter was provided by the caller, or created by SqlHelper</param>
/// <returns>SqlDataReader containing the results of the command</returns>
private static SqlDataReader ExecuteReader(SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters, SqlConnectionOwnership connectionOwnership)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
PrepareCommand(cmd, connection, transaction, commandType, commandText, commandParameters);
//create a reader
SqlDataReader dr;
// call ExecuteReader with the appropriate CommandBehavior
if (connectionOwnership == SqlConnectionOwnership.External)
{
dr = cmd.ExecuteReader();
}
else
{
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
return dr;
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the database specified in
/// the connection string.
/// </summary>
/// <remarks>
/// e.g.:
/// SqlDataReader dr = ExecuteReader(connString, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(string connectionString, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteReader(connectionString, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// SqlDataReader dr = ExecuteReader(connString, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create & open a SqlConnection
SqlConnection cn = new SqlConnection(connectionString);
cn.Open();
try
{
//call the private overload that takes an internally owned connection in place of the connection string
return ExecuteReader(cn, null, commandType, commandText, commandParameters, SqlConnectionOwnership.Internal);
}
catch (Exception e)
{
//if we fail to return the SqlDatReader, we need to close the connection ourselves
cn.Close();
throw e;
}
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the database specified in
/// the connection string using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// SqlDataReader dr = ExecuteReader(connString, "GetOrders", 24, 36);
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(string connectionString, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteReader(connectionString, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection.
/// </summary>
/// <remarks>
/// e.g.:
/// SqlDataReader dr = ExecuteReader(conn, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(SqlConnection connection, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteReader(connection, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// SqlDataReader dr = ExecuteReader(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//pass through the call to the private overload using a null transaction value and an externally owned connection
return ExecuteReader(connection, (SqlTransaction)null, commandType, commandText, commandParameters, SqlConnectionOwnership.External);
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection
/// using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// SqlDataReader dr = ExecuteReader(conn, "GetOrders", 24, 36);
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(SqlConnection connection, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
AssignParameterValues(commandParameters, parameterValues);
return ExecuteReader(connection, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteReader(connection, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction.
/// </summary>
/// <remarks>
/// e.g.:
/// SqlDataReader dr = ExecuteReader(trans, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(SqlTransaction transaction, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteReader(transaction, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// SqlDataReader dr = ExecuteReader(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//pass through to private overload, indicating that the connection is owned by the caller
return ExecuteReader(transaction.Connection, transaction, commandType, commandText, commandParameters, SqlConnectionOwnership.External);
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified
/// SqlTransaction using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// SqlDataReader dr = ExecuteReader(trans, "GetOrders", 24, 36);
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>a SqlDataReader containing the resultset generated by the command</returns>
public static SqlDataReader ExecuteReader(SqlTransaction transaction, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
AssignParameterValues(commandParameters, parameterValues);
return ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteReader(transaction, CommandType.StoredProcedure, spName);
}
}
#endregion ExecuteReader
#region ExecuteScalar
/// <summary>
/// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the database specified in
/// the connection string.
/// </summary>
/// <remarks>
/// e.g.:
/// int orderCount = (int)ExecuteScalar(connString, CommandType.StoredProcedure, "GetOrderCount");
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteScalar(connectionString, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a 1x1 resultset) against the database specified in the connection string
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// int orderCount = (int)ExecuteScalar(connString, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create & open a SqlConnection, and dispose of it after we are done.
using (SqlConnection cn = new SqlConnection(connectionString))
{
cn.Open();
//call the overload that takes a connection in place of the connection string
return ExecuteScalar(cn, commandType, commandText, commandParameters);
}
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the database specified in
/// the connection string using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// int orderCount = (int)ExecuteScalar(connString, "GetOrderCount", 24, 36);
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(string connectionString, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the provided SqlConnection.
/// </summary>
/// <remarks>
/// e.g.:
/// int orderCount = (int)ExecuteScalar(conn, CommandType.StoredProcedure, "GetOrderCount");
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteScalar(connection, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a 1x1 resultset) against the specified SqlConnection
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// int orderCount = (int)ExecuteScalar(conn, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
//execute the command & return the results
object retval = cmd.ExecuteScalar();
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
return retval;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified SqlConnection
/// using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// int orderCount = (int)ExecuteScalar(conn, "GetOrderCount", 24, 36);
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(SqlConnection connection, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteScalar(connection, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns a 1x1 resultset and takes no parameters) against the provided SqlTransaction.
/// </summary>
/// <remarks>
/// e.g.:
/// int orderCount = (int)ExecuteScalar(trans, CommandType.StoredProcedure, "GetOrderCount");
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(SqlTransaction transaction, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteScalar(transaction, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a 1x1 resultset) against the specified SqlTransaction
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// int orderCount = (int)ExecuteScalar(trans, CommandType.StoredProcedure, "GetOrderCount", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
//execute the command & return the results
object retval = cmd.ExecuteScalar();
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
return retval;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a 1x1 resultset) against the specified
/// SqlTransaction using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// int orderCount = (int)ExecuteScalar(trans, "GetOrderCount", 24, 36);
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>an object containing the value in the 1x1 resultset generated by the command</returns>
public static object ExecuteScalar(SqlTransaction transaction, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteScalar(transaction, CommandType.StoredProcedure, spName);
}
}
#endregion ExecuteScalar
#region ExecuteXmlReader
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlConnection.
/// </summary>
/// <remarks>
/// e.g.:
/// XmlReader r = ExecuteXmlReader(conn, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
/// <returns>an XmlReader containing the resultset generated by the command</returns>
public static XmlReader ExecuteXmlReader(SqlConnection connection, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteXmlReader(connection, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the specified SqlConnection
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// XmlReader r = ExecuteXmlReader(conn, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an XmlReader containing the resultset generated by the command</returns>
public static XmlReader ExecuteXmlReader(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters);
//create the DataAdapter & DataSet
XmlReader retval = cmd.ExecuteXmlReader();
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
return retval;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified SqlConnection
/// using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// XmlReader r = ExecuteXmlReader(conn, "GetOrders", 24, 36);
/// </remarks>
/// <param name="connection">a valid SqlConnection</param>
/// <param name="spName">the name of the stored procedure using "FOR XML AUTO"</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>an XmlReader containing the resultset generated by the command</returns>
public static XmlReader ExecuteXmlReader(SqlConnection connection, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName);
}
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset and takes no parameters) against the provided SqlTransaction.
/// </summary>
/// <remarks>
/// e.g.:
/// XmlReader r = ExecuteXmlReader(trans, CommandType.StoredProcedure, "GetOrders");
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
/// <returns>an XmlReader containing the resultset generated by the command</returns>
public static XmlReader ExecuteXmlReader(SqlTransaction transaction, CommandType commandType, string commandText)
{
//pass through the call providing null for the set of SqlParameters
return ExecuteXmlReader(transaction, commandType, commandText, (SqlParameter[])null);
}
/// <summary>
/// Execute a SqlCommand (that returns a resultset) against the specified SqlTransaction
/// using the provided parameters.
/// </summary>
/// <remarks>
/// e.g.:
/// XmlReader r = ExecuteXmlReader(trans, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
/// <param name="commandText">the stored procedure name or T-SQL command using "FOR XML AUTO"</param>
/// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
/// <returns>an XmlReader containing the resultset generated by the command</returns>
public static XmlReader ExecuteXmlReader(SqlTransaction transaction, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
//create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters);
//create the DataAdapter & DataSet
XmlReader retval = cmd.ExecuteXmlReader();
// detach the SqlParameters from the command object, so they can be used again.
cmd.Parameters.Clear();
return retval;
}
/// <summary>
/// Execute a stored procedure via a SqlCommand (that returns a resultset) against the specified
/// SqlTransaction using the provided parameter values. This method will query the database to discover the parameters for the
/// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
/// </summary>
/// <remarks>
/// This method provides no access to output parameters or the stored procedure's return value parameter.
///
/// e.g.:
/// XmlReader r = ExecuteXmlReader(trans, "GetOrders", 24, 36);
/// </remarks>
/// <param name="transaction">a valid SqlTransaction</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
/// <returns>a dataset containing the resultset generated by the command</returns>
public static XmlReader ExecuteXmlReader(SqlTransaction transaction, string spName, params object[] parameterValues)
{
//if we receive parameter values, we need to figure out where they go
if ((parameterValues != null) && (parameterValues.Length > 0))
{
//pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);
//assign the provided values to these parameters based on parameter order
AssignParameterValues(commandParameters, parameterValues);
//call the overload that takes an array of SqlParameters
return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
}
//otherwise we can just call the SP without params
else
{
return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName);
}
}
#endregion ExecuteXmlReader
}
/// <summary>
/// SqlHelperParameterCache provides functions to leverage a static cache of procedure parameters, and the
/// ability to discover parameters for stored procedures at run-time.
/// </summary>
public sealed class SqlHelperParameterCache
{
#region private methods, variables, and constructors
//Since this class provides only static methods, make the default constructor private to prevent
//instances from being created with "new SqlHelperParameterCache()".
private SqlHelperParameterCache() { }
private static Hashtable paramCache = Hashtable.Synchronized(new Hashtable());
/// <summary>
/// resolve at run time the appropriate set of SqlParameters for a stored procedure
/// </summary>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="includeReturnValueParameter">whether or not to include their return value parameter</param>
/// <returns></returns>
private static SqlParameter[] DiscoverSpParameterSet(string connectionString, string spName, bool includeReturnValueParameter)
{
using (SqlConnection cn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(spName, cn))
{
cn.Open();
cmd.CommandType = CommandType.StoredProcedure;
SqlCommandBuilder.DeriveParameters(cmd);
if (!includeReturnValueParameter)
{
cmd.Parameters.RemoveAt(0);
}
SqlParameter[] discoveredParameters = new SqlParameter[cmd.Parameters.Count]; ;
cmd.Parameters.CopyTo(discoveredParameters, 0);
return discoveredParameters;
}
}
//deep copy of cached SqlParameter array
private static SqlParameter[] CloneParameters(SqlParameter[] originalParameters)
{
SqlParameter[] clonedParameters = new SqlParameter[originalParameters.Length];
for (int i = 0, j = originalParameters.Length; i < j; i++)
{
clonedParameters[i] = (SqlParameter)((ICloneable)originalParameters[i]).Clone();
}
return clonedParameters;
}
#endregion private methods, variables, and constructors
#region caching functions
/// <summary>
/// add parameter array to the cache
/// </summary>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <param name="commandParameters">an array of SqlParamters to be cached</param>
public static void CacheParameterSet(string connectionString, string commandText, params SqlParameter[] commandParameters)
{
string hashKey = connectionString + ":" + commandText;
paramCache[hashKey] = commandParameters;
}
/// <summary>
/// retrieve a parameter array from the cache
/// </summary>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="commandText">the stored procedure name or T-SQL command</param>
/// <returns>an array of SqlParamters</returns>
public static SqlParameter[] GetCachedParameterSet(string connectionString, string commandText)
{
string hashKey = connectionString + ":" + commandText;
SqlParameter[] cachedParameters = (SqlParameter[])paramCache[hashKey];
if (cachedParameters == null)
{
return null;
}
else
{
return CloneParameters(cachedParameters);
}
}
#endregion caching functions
#region Parameter Discovery Functions
/// <summary>
/// Retrieves the set of SqlParameters appropriate for the stored procedure
/// </summary>
/// <remarks>
/// This method will query the database for this information, and then store it in a cache for future requests.
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <returns>an array of SqlParameters</returns>
public static SqlParameter[] GetSpParameterSet(string connectionString, string spName)
{
return GetSpParameterSet(connectionString, spName, false);
}
/// <summary>
/// Retrieves the set of SqlParameters appropriate for the stored procedure
/// </summary>
/// <remarks>
/// This method will query the database for this information, and then store it in a cache for future requests.
/// </remarks>
/// <param name="connectionString">a valid connection string for a SqlConnection</param>
/// <param name="spName">the name of the stored procedure</param>
/// <param name="includeReturnValueParameter">a bool value indicating whether the return value parameter should be included in the results</param>
/// <returns>an array of SqlParameters</returns>
public static SqlParameter[] GetSpParameterSet(string connectionString, string spName, bool includeReturnValueParameter)
{
string hashKey = connectionString + ":" + spName + (includeReturnValueParameter ? ":include ReturnValue Parameter" : "");
SqlParameter[] cachedParameters;
cachedParameters = (SqlParameter[])paramCache[hashKey];
if (cachedParameters == null)
{
cachedParameters = (SqlParameter[])(paramCache[hashKey] = DiscoverSpParameterSet(connectionString, spName, includeReturnValueParameter));
}
return CloneParameters(cachedParameters);
}
#endregion Parameter Discovery Functions
}
}
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Data.SqlClient;
namespace test.Extension
{
public static partial class DataTableExtension
{
public static List<string> GetFields(this DataTable dataTable)
{
List<string> lstFieldName = new List<string>();
foreach (DataColumn column in dataTable.Columns)
{
lstFieldName.Add(column.ColumnName);
}
return lstFieldName;
}
public static string GetInsertCommand(this DataTable dataTable, string tableName)
{
List<string> lstFieldName = dataTable.GetFields();
StringBuilder sb = new StringBuilder();
sb.Append(" INSERT INTO ");
sb.Append(tableName);
sb.Append(" ( ");
sb.Append(lstFieldName.JoinString(","));
sb.Append(") values (");
sb.Append("@");
sb.Append(lstFieldName.JoinString(",@"));
sb.Append(")");
return sb.ToString();
}
public static string GetUpdateCommand(List<string> tabColumns, string tableName, string primaryKeyName)
{
List<string> lstFieldName = new List<string>();
tabColumns.ForEach(field =>
{
if (field != primaryKeyName) lstFieldName.Add($"{field} = @{field}");
});
StringBuilder sb = new StringBuilder();
sb.Append(" Update ");
sb.Append(tableName);
sb.Append(" Set ");
sb.Append(lstFieldName.JoinString(","));
sb.Append($" Where {primaryKeyName} = @{primaryKeyName};");
return sb.ToString();
}
public static string GetUpdateCommand(this DataTable dataTable, string tableName, string primaryKeyName)
{
List<string> lstFieldName = new List<string>();
foreach (DataColumn column in dataTable.Columns)
{
if (column.ColumnName == primaryKeyName) continue;
lstFieldName.Add($"{column.ColumnName} = @{column.ColumnName}");
}
StringBuilder sb = new StringBuilder();
sb.Append(" Update ");
sb.Append(tableName);
sb.Append(" Set ");
sb.Append(lstFieldName.JoinString(","));
sb.Append($" Where {primaryKeyName} = @{primaryKeyName};");
return sb.ToString();
}
public static KeyValuePair<string, IEnumerable<Dictionary<string, object>>> GetInsertCommandWithParam(this DataTable dataTable, string tableName)
{
return new KeyValuePair<string, IEnumerable<Dictionary<string, object>>>(dataTable.GetInsertCommand(tableName), dataTable.GetFieldValues());
}
public static IEnumerable<Dictionary<string, object>> GetFieldValues(this DataTable dataTable)
{
var lstDic = new List<Dictionary<string, object>>();
for (var i = 0; i < dataTable.Rows.Count; i++)
{
var row = dataTable.Rows[i];
var dic = new Dictionary<string, object>();
for (var j = 0; j < dataTable.Columns.Count; j++)
{
var oValue = row[j];
dic.Add(dataTable.Columns[j].ColumnName, oValue != System.DBNull.Value ? oValue : null);
}
lstDic.Add(dic);
}
return lstDic;
}
public static List<SqlParameter[]> GetSqlParameter(this DataTable dataTable)
{
var lstParam = new List<SqlParameter[]>();
for (var i = 0; i < dataTable.Rows.Count; i++)
{
var parameters = new List<SqlParameter>();
for (var j = 0; j < dataTable.Columns.Count; j++)
{
parameters.Add(new SqlParameter(dataTable.Columns[j].ColumnName, dataTable.Rows[i][j]));
}
lstParam.Add(parameters.ToArray());
}
return lstParam;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace test.Extension
{
public static class ExpressionExtension
{
public struct BinaryExpressionInfo
{
public BinaryExpression Body;
public MemberExpression Left;
public Expression Right;
public string LeftName;
public object GetRightValue()
{
if (this.Right is MemberExpression)
{
return this.getMemberExpressionValue((MemberExpression)this.Right);
}
if (this.Right is ConstantExpression)
{
return this.getConstantExpressionValue((ConstantExpression)this.Right);
}
throw new Exception("未实现的Expression类型:" + this.Right.GetType().FullName);
}
private object getConstantExpressionValue(ConstantExpression r)
{
return r.Value;
}
private object getMemberExpressionValue(MemberExpression r)
{
if (r.Expression is ConstantExpression)
{
object rightValue = ((ConstantExpression)r.Expression).Value;
return ((FieldInfo)r.Member).GetValue(rightValue);
}
if (r.Expression is MemberExpression)
{
return Expression.Lambda(r, new ParameterExpression[0]).Compile().DynamicInvoke(new object[0]);
}
throw new Exception("未能处理表达式的右侧的值");
}
}
public static string GetOneName(this Expression exp)
{
return ((PropertyInfo)((MemberExpression)((LambdaExpression)exp).Body).Member).Name;
}
public static ExpressionExtension.BinaryExpressionInfo GetBinaryExpressionInfo(this Expression exp)
{
ExpressionExtension.BinaryExpressionInfo info = default(ExpressionExtension.BinaryExpressionInfo);
info.Body = (BinaryExpression)((LambdaExpression)exp).Body;
info.Left = (MemberExpression)info.Body.Left;
info.Right = info.Body.Right;
info.LeftName = info.Left.Member.Name;
return info;
}
public static string JoinString<T>(this IEnumerable<T> source, string separator)
{
return string.Join<T>(separator, source);
}
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test.Extension
{
public static partial class DataTableExtension
{
#region 公共方法(扩展DataTable)
/// <summary>
/// DataTable转换成T
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="table">需转换的数据table</param>
/// <returns></returns>
public static T ToModel<T>(this DataTable table) where T : new()
{
if (table == null || table.Columns.Count == 0 || table.Rows.Count == 0) return default(T);
var propertyInfos = from propertyInfo in typeof(T).GetProperties()
where table.Columns.Contains(propertyInfo.Name)
select propertyInfo;
return DataRowToModel<T>(propertyInfos, table.Rows[0]);
//T entity = new T();
//DataRow dr = table.Rows[0];
//foreach (var pi in propertyInfos)
//{
// if (!pi.CanWrite) continue;
// object value = dr[pi.Name];
// if (value != DBNull.Value)
// pi.SetValue(entity, ChangeType(dr[pi.Name], pi.PropertyType), null);
//}
//return entity;
}
/// <summary>
/// DataTable转换成List<T>
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="table">需转换的数据table</param>
/// <returns></returns>
public static List<T> ToModelList<T>(this DataTable table) where T : new()
{
List<T> entities = new List<T>();
if (table == null || table.Columns.Count == 0 || table.Rows.Count == 0) return entities;
var propertyInfos = from propertyInfo in typeof(T).GetProperties()
where table.Columns.Contains(propertyInfo.Name)
select propertyInfo;
foreach (DataRow dr in table.Rows)
{
entities.Add(DataRowToModel<T>(propertyInfos, dr));
}
return entities;
//foreach (DataRow dr in table.Rows)
//{
// T entity = new T();
// foreach (var pi in propertyInfos)
// {
// if (!pi.CanWrite) continue;
// object value = dr[pi.Name];
// if (value != DBNull.Value)
// pi.SetValue(entity, ChangeType(dr[pi.Name], pi.PropertyType), null);
// }
// entities.Add(entity);
//}
//return entities;
}
#endregion 公共方法(扩展DataTable)
#region 私有方法(Convert.ChangeType处理Nullable<>和非Nullable<>)
private static T DataRowToModel<T>(IEnumerable<System.Reflection.PropertyInfo> propertyInfos, DataRow dataRow) where T : new()
{
T entity = new T();
foreach (var pi in propertyInfos)
{
if (!pi.CanWrite) continue;
object value = dataRow[pi.Name];
if (value != DBNull.Value || pi.PropertyType == typeof(string)) // 为null的字符串需要转化为""
pi.SetValue(entity, ChangeType(dataRow[pi.Name], pi.PropertyType), null);
}
return entity;
}
/// <summary>
/// 类型转换(包含Nullable<>和非Nullable<>转换)
/// </summary>
/// <param name="value"></param>
/// <param name="conversionType"></param>
/// <returns></returns>
private static object ChangeType(object value, Type conversionType)
{
// Note: This if block was taken from Convert.ChangeType as is, and is needed here since we're
// checking properties on conversionType below.
if (conversionType == null)
{
throw new ArgumentNullException("conversionType");
} // end if
// If it's not a nullable type, just pass through the parameters to Convert.ChangeType
if (conversionType.IsGenericType &&
conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
{
return null;
}
// It's a nullable type, and not null, so that means it can be converted to its underlying type,
// so overwrite the passed-in conversion type with this underlying type
System.ComponentModel.NullableConverter nullableConverter = new System.ComponentModel.NullableConverter(conversionType);
conversionType = nullableConverter.UnderlyingType;
}
// Now that we've guaranteed conversionType is something Convert.ChangeType can handle (i.e. not a
// nullable type), pass the call on to Convert.ChangeType
return Convert.ChangeType(value, conversionType);
}
#endregion 私有方法(Convert.ChangeType处理Nullable<>和非Nullable<>)
}
}

namespace test
{
partial class FrmDbo
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnDapper = new System.Windows.Forms.Button();
this.btnFluent = new System.Windows.Forms.Button();
this.btnSqlHelper = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.btnClear = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnDapper
//
this.btnDapper.Location = new System.Drawing.Point(25, 23);
this.btnDapper.Name = "btnDapper";
this.btnDapper.Size = new System.Drawing.Size(75, 23);
this.btnDapper.TabIndex = 1;
this.btnDapper.Text = "RunDraaper";
this.btnDapper.UseVisualStyleBackColor = true;
this.btnDapper.Click += new System.EventHandler(this.btnDapper_Click);
//
// btnFluent
//
this.btnFluent.Location = new System.Drawing.Point(128, 23);
this.btnFluent.Name = "btnFluent";
this.btnFluent.Size = new System.Drawing.Size(75, 23);
this.btnFluent.TabIndex = 2;
this.btnFluent.Text = "RunFluent";
this.btnFluent.UseVisualStyleBackColor = true;
this.btnFluent.Click += new System.EventHandler(this.btnFluent_Click);
//
// btnSqlHelper
//
this.btnSqlHelper.Location = new System.Drawing.Point(231, 23);
this.btnSqlHelper.Name = "btnSqlHelper";
this.btnSqlHelper.Size = new System.Drawing.Size(75, 23);
this.btnSqlHelper.TabIndex = 3;
this.btnSqlHelper.Text = "RunSqlHelper";
this.btnSqlHelper.UseVisualStyleBackColor = true;
this.btnSqlHelper.Click += new System.EventHandler(this.btnSqlHelper_Click);
//
// textBox1
//
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textBox1.Location = new System.Drawing.Point(12, 55);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(420, 241);
this.textBox1.TabIndex = 4;
//
// btnClear
//
this.btnClear.Location = new System.Drawing.Point(335, 23);
this.btnClear.Name = "btnClear";
this.btnClear.Size = new System.Drawing.Size(75, 23);
this.btnClear.TabIndex = 5;
this.btnClear.Text = "清空";
this.btnClear.UseVisualStyleBackColor = true;
this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
//
// FrmDbo
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(444, 308);
this.Controls.Add(this.btnClear);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.btnSqlHelper);
this.Controls.Add(this.btnFluent);
this.Controls.Add(this.btnDapper);
this.Name = "FrmDbo";
this.Text = "FrmOrm";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button btnDapper;
private System.Windows.Forms.Button btnFluent;
private System.Windows.Forms.Button btnSqlHelper;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button btnClear;
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Windows.Forms;
using test.Extension;
using test.Tester;
namespace test
{
public partial class FrmDbo : Form
{
public FrmDbo()
{
InitializeComponent();
}
private void btnQuery_Click(object sender, EventArgs e)
{
ITester tester = new TDapper();
DataTable dtBom = null;
TimeWatch.Wrap("获取Bom5000", () => { dtBom = tester.GetDataTable("Select top(5000) * From OrderStyleBOM"); });
var sql = "Update OrderStyleBOM Set SubmitDate = @SubmitDate,LastModifiedMemo = @LastModifiedMemo,Remark = @Remark Where UID = @UID";
Dictionary<string, object> data = new Dictionary<string, object>() { { "SubmitDate", DateTime.Now }, { "LastModifiedMemo", "更新测试" }, { "UID", Guid.Parse("F25701F7-D877-46CB-986D-991090168B97") }, { "Remark", null } };
tester.Execute(sql, data);
var upCommand = dtBom.GetUpdateCommand("OrderStyleBOM", "UID");
tester.Update(upCommand, dtBom);
var dtInsert = tester.GetDataTable("Select top(100) * From OrderStyleBOM order by ID");
foreach (DataRow row in dtInsert.Rows)
{
row["UID"] = Guid.NewGuid();
}
var insertCommand = dtBom.GetInsertCommand("OrderStyleBOM");
tester.Insert(insertCommand, dtInsert);
}
private void btnDapper_Click(object sender, EventArgs e)
{
ITester tester = new TDapper();
Tester(sender, tester);
}
private void btnFluent_Click(object sender, EventArgs e)
{
ITester tester = new TFluentData();
Tester(sender, tester);
}
private void btnSqlHelper_Click(object sender, EventArgs e)
{
ITester tester = new TSqlHelper();
Tester(sender, tester);
}
private void Tester(object sender, ITester tester)
{
var button = (Button)sender;
button.Enabled = false;
Test1(tester);
button.Enabled = true;
}
private void Test1(ITester tester)
{
dicTimes.Clear();
TimeWatch timeWatch = TimeWatch.Start();
var sql = "Update OrderStyleBOM Set SubmitDate = @SubmitDate,LastModifiedMemo = @LastModifiedMemo,Remark = @Remark Where UID = @UID";
Dictionary<string, object> data = new Dictionary<string, object>() { { "SubmitDate", DateTime.Now }, { "LastModifiedMemo", "更新测试" }, { "UID", Guid.Parse("F25701F7-D877-46CB-986D-991090168B97") }, { "Remark", null } };
tester.Execute(sql, data);
ShowTestTime("更新1条记录", timeWatch);
#region Select 5000
DataTable dtBom = tester.GetDataTable("Select top(5000) * From OrderStyleBOM");
ShowTestTime("查询5000条记录", timeWatch);
#endregion
var dtQuery = tester.GetDataTable("Select top(100) * From OrderStyleBOM order by ID");
#region Update 100
var upCommand = dtBom.GetUpdateCommand("OrderStyleBOM", "UID");
tester.Update(upCommand, dtQuery);
ShowTestTime("更新100条记录", timeWatch);
#endregion
#region Insert 100
foreach (DataRow row in dtQuery.Rows) row["UID"] = Guid.NewGuid(); //
tester.Insert(dtQuery.GetInsertCommand("OrderStyleBOM"), dtQuery);
ShowTestTime("插入100条记录", timeWatch);
#endregion
ShowTester(tester.GetType().Name);
}
Dictionary<string, double> dicTimes = new Dictionary<string, double>();
private void ShowTestTime(string text, TimeWatch timeWatch)
{
dicTimes.Add(text, timeWatch.TimeSpan.TotalMilliseconds);
timeWatch.ShowLog(text, true);
}
private void ShowTester(string testerName)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"{ testerName} 测试完成:");
foreach (var dic in dicTimes)
sb.AppendLine($"{dic.Key} 耗时:{dic.Value}");
sb.AppendLine("================================================");
textBox1.Text += sb.ToString();
}
private void btnClear_Click(object sender, EventArgs e)
{
textBox1.Text = "";
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test
{
static class Program
{
/*
* 抛出异常:
托管调试助手 "ContextSwitchDeadlock"
CLR 无法从 COM 上下文 0xa62c80 转换为 COM 上下文 0xa62b10,这种状态已持续 60 秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作。
这种情况通常会影响到性能,甚至可能导致应用程序不响应或者使用的内存随时间不断累积。要避免此问题,所有单线程单元(STA)线程都应使用泵式等待基元(如 CoWaitForMultipleHandles),并在运行时间很长的操作过程中定期发送消息。
在调试菜单中的异常选项,在Managed Debugging Assistants 中将ContextSwitchDeadlock后面的第一个勾给去掉就可以了。
*/
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmDbo());
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("test")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("1447f8df-e552-40dd-8f02-b55d75fbc77a")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace test.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("test.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
\ No newline at end of file
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace test.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
using Dapper;
using System;
using System.Collections.Generic;
using System.Data;
using test.DBO;
using test.Extension;
namespace test.Tester
{
public class TDapper : ITester
{
public void Delete(List<int> ids)
{
throw new NotImplementedException();
}
public DataTable GetDataTable(string sql)
{
using (DbDapper dbDapper = new DbDapper(TData.Conn))
{
return dbDapper.GetDataTable(sql);
}
}
public void Execute(string sql, Dictionary<string, object> param)
{
using (DbDapper dbDapper = new DbDapper(TData.Conn))
{
dbDapper.Trans((conn, tran) =>
{
conn.Execute(sql, param, tran);
});
}
}
/// <summary>
/// 经测试 7K 的时候.默认30s不够用
///
/// </summary>
/// <param name="sql"></param>
/// <param name="dataTable"></param>
public void Update(string sql, DataTable dataTable)
{
var lstFieldValues = dataTable.GetFieldValues();
using (DbDapper dbDapper = new DbDapper(TData.Conn))
{
dbDapper.Trans((conn, tran) =>
{
foreach (var item in lstFieldValues)
conn.Execute(sql, item, tran);
});
}
}
public void Insert(string sql, DataTable dataTable)
{
var lstFieldValues = dataTable.GetFieldValues();
using (DbDapper dbDapper = new DbDapper(TData.Conn))
{
dbDapper.Trans((conn, tran) =>
{
foreach (var item in lstFieldValues)
conn.Execute(sql, item, tran);
});
}
}
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test.Tester
{
/// <summary>
/// 数据测试,环境可以认为是相同的
/// </summary>
public class TData
{
/// <summary>
/// 测试用到的表
/// </summary>
public static List<string> Tables = new List<string>() { "OrderStyleBOM", "MaterialCalculation", "MX_Material", "OrderSendProjectWorkMaterial", "OrderStyleMaterial", "MaterialCalculationDetail" };
/// <summary>
/// 数据库连接
/// </summary>
public const string Conn = "Password=sa;Persist Security Info=True;User ID=sa;Initial Catalog=tempdb;Data Source=jhdsoft.gicp.net,3204";
}
/// <summary>
/// 需要测试的项目
/// </summary>
public interface ITester
{
DataTable GetDataTable(string sql);
void Execute(string sql, Dictionary<string, object> param);
void Insert(string sql, DataTable dataTable);
void Update(string sql, DataTable dataTable);
void Delete(List<int> ids);
}
}
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentData;
using test.DBO;
using test.Extension;
namespace test.Tester
{
public class TFluentData : ITester
{
public void Delete(List<int> ids)
{
throw new NotImplementedException();
}
public void Execute(string sql, Dictionary<string, object> param)
{
DbFluentData dbFluentData = new DbFluentData(TData.Conn);
dbFluentData.Execute(sql, param);
}
public DataTable GetDataTable(string sql)
{
DbFluentData dbFluentData = new DbFluentData(TData.Conn);
var tables = dbFluentData.SelectMany<DataTable>(sql, null);
return tables.Count > 0 ? tables[0] : null;
}
public void Insert(string sql, DataTable dataTable)
{
var lstFieldValues = dataTable.GetFieldValues();
DbFluentData dbFluentData = new DbFluentData(TData.Conn);
dbFluentData.Execute(sql, lstFieldValues);
}
public void Update(string sql, DataTable dataTable)
{
var lstFieldValues = dataTable.GetFieldValues();
DbFluentData dbFluentData = new DbFluentData(TData.Conn);
dbFluentData.Execute(sql, lstFieldValues);
}
}
}
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using test.DBO;
using test.Extension;
namespace test.Tester
{
public class TSqlHelper : ITester
{
public void Delete(List<int> ids)
{
}
public void Execute(string sql, Dictionary<string, object> param)
{
var parameters = ParseDic(param);
DbSqlHelper.ExecuteNonQuery(TData.Conn, CommandType.Text, sql, parameters);
}
public DataTable GetDataTable(string sql)
{
var dataSet = DbSqlHelper.ExecuteDataset(TData.Conn, CommandType.Text, sql);
return dataSet.Tables[0];
}
public void Insert(string sql, DataTable dataTable)
{
var lstParam = dataTable.GetSqlParameter();
using (SqlConnection cn = new SqlConnection(TData.Conn))
{
cn.Open();
var tran = cn.BeginTransaction();
foreach (var param in lstParam)
{
DbSqlHelper.ExecuteNonQuery(tran, CommandType.Text, sql, param);
}
}
}
public void Update(string sql, DataTable dataTable)
{
var lstParam = dataTable.GetSqlParameter();
using (SqlConnection cn = new SqlConnection(TData.Conn))
{
cn.Open();
var tran = cn.BeginTransaction();
foreach (var param in lstParam)
{
DbSqlHelper.ExecuteNonQuery(tran, CommandType.Text, sql, param);
}
}
}
private SqlParameter[] ParseDic(Dictionary<string, object> param)
{
List<SqlParameter> parameters = new List<SqlParameter>();
foreach (var dic in param)
parameters.Add(new SqlParameter(dic.Key, dic.Value ?? System.DBNull.Value));
return parameters.ToArray();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test
{
public class TimeWatch
{
private DateTime? dtStart, dtEnd;
public static TimeWatch Start()
{
return new TimeWatch();
}
private TimeWatch()
{
ReStart();
}
public void Stop()
{
dtEnd = DateTime.Now;
}
/// <summary>
/// 时间间隔
/// </summary>
public TimeSpan TimeSpan
{
get
{
return (TimeSpan)((dtEnd == null ? DateTime.Now : dtEnd) - dtStart);
}
}
public void ReStart()
{
dtStart = DateTime.Now;
}
public void ShowLog(string text, bool isReset = false)
{
ShowTime(text, this);
if (isReset) ReStart();
}
/// <summary>
/// 写测试日志
/// </summary>
/// <param name="name"></param>
/// <param name="action"></param>
public static void Wrap(string name, Action action)
{
var watch = TimeWatch.Start();
action();
ShowTime(name, watch);
}
private static void ShowTime(string name, TimeWatch timeWatch)
{
Console.WriteLine($"【{name}】:{timeWatch.TimeSpan.TotalMilliseconds} ms");
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Dapper" version="2.0.78" targetFramework="net472" />
<package id="FluentData" version="3.0.1.0" targetFramework="net472" />
</packages>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1447F8DF-E552-40DD-8F02-B55D75FBC77A}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>test</RootNamespace>
<AssemblyName>test</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Dapper, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Dapper.2.0.78\lib\net461\Dapper.dll</HintPath>
</Reference>
<Reference Include="FluentData, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\FluentData.3.0.1.0\lib\FluentData.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DBO\DbFluentData.cs" />
<Compile Include="DBO\DbSqlHelper.cs" />
<Compile Include="Extension\DataTableExtension.cs" />
<Compile Include="Extension\ExpressionExtension.cs" />
<Compile Include="Extension\Table2Model.cs" />
<Compile Include="FrmDbo.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FrmDbo.Designer.cs">
<DependentUpon>FrmDbo.cs</DependentUpon>
</Compile>
<Compile Include="DBO\DbDapper.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tester\TDapper.cs" />
<Compile Include="Tester\TFluentData.cs" />
<Compile Include="Tester\TSqlHelper.cs" />
<Compile Include="Tester\TData.cs" />
<Compile Include="TimeWatch.cs" />
<EmbeddedResource Include="FrmDbo.resx">
<DependentUpon>FrmDbo.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment