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;
}
}
}
}
This diff is collapsed.
This diff is collapsed.
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