“啊!你在用ORM?会不会性能很差啊?”
用数字来说话,打破模糊的、传言的印象。
标题提到的组件的增删改查的测试都实现了测试代码,所以除了测试外,也可以把此项目作为各个组件的入门参考demo。
源码下载:https://github.com/alifellod/DbAccessLibTest/archive/master.zip
git地址:https://github.com/alifellod/DbAccessLibTest 欢迎园友贡献改进代码。
项目使用的是.Net Framework 4.0可以使用2010或2012打开。
默认测试数据库使用SqlServer
测试前,请先创建数据表Test(使用名为Test的数据库,如果不用这个数据库,请更改数据库连接字符串)
class="code_img_closed" id="code_img_closed_11342730-6925-4b73-ae75-28e145087561" alt="" />
logs_code_hide('11342730-6925-4b73-ae75-28e145087561',event)" style="display:none">
CREATE TABLE [dbo].
[Test]
(
[RowId] [int] IDENTITY(
1,
1)
NOT NULL,
[Guid] [varchar](
50)
primary key NOT NULL,
[Content] [nvarchar](
500)
NULL,
[CreateDate] [datetime] NULL default getdate(),
[EditDate] [datetime] NULL
)
View Code
测试前清表:truncatetable Test
默认连接字符串是:Data Source=.;Initial Catalog=Test;Integrated Security=True
此程度测试代码使用了接口规范,并没有为了省事耦合在程序里,因此编写修改测试代码非常简单,所以也希望各位园友自己写上一段测试测试。
由于这些组件基本都是第一次使用,所以可能导致部分组件测试代码编写并不合理,敬请指点。
注意:各组件的测试均采用一样的测试思路,也即ORM对ORM,SQL对SQL,循环也是一样的循环。
不必拘泥于15和23的区别,而且要区别10和100的区别,也就是在一个数量级别之间比较。
线程我分别写了Task、ThreadPool和Thread的执行方式,根据自己的喜欢选择。
Task可以很好的取消创建的线程,ThreadPool测试会较为稳定,Thread很容易导致SQL
连接池爆破。
测试之前,先预热一下——各个组件进行一定数量执行查询。
先看两张测试图。
数据格式:平均值-最高值-最低值
测试顺序:增、改、删
100“线程” 查询10次 增删改
ClownFish
Moon
PDF
增
23-96-2
21-76-6
8-25-4
删
16-49-2
15-37-5
4-18-2
改
46-116-3
23-56-3
7-33-3
CYQOrm
EFOrm
MoonOrm
MySoftOrm
NHibernateOrm
PDFOrm
XCodeOrm
增
419-560-311
23-71-8
10-64-3
46-102-24
21-47-7
12-31-4
15-60-9
删
889-1611-493
61-137-17
10-29-3
41-267-15
41-103-9
20-54-3
340-623-173
改
428-1112-255
37-113-15
5-15-2
110-195-52
37-128-7
17-50-3
364-476-246
1000“线程” 查询10次增删改
ClownFish
Moon
PDF
增
9-276-2
13-49-2
7-44-3
删
22-125-2
7-43-3
9-41-3
改
20-299-2
10-123-3
8-66-2
CYQOrm
EFOrm
MoonOrm
MySoftOrm
NHibernateOrm
PDFOrm
XCodeOrm
增
591-1376-227
29-306-9
6-52-3
50-386-11
12-259-4
10-48-3
14-231-8
删
680-1107-382
43-321-11
14-95-2
78-386-13
45-237-7
22-90-4
362-729-177
改
553-867-233
59-334-12
27-215-14
106-647-18
42-294-4
17-128-3
410-755-199
查询测试,数据行100W
100“线程” 查询返回Top 100
使用没有索引的列RowId排序
ClownFish
Moon
PDF
查
2-19-1
1-9-0
1-47-0
查询采用的根据组件提供的分页或者Top查询功能。
使用没有索引的列RowId排序
CYQOrm
EFOrm
MoonOrm
MySoftOrm
NHibernateOrm
PDFOrm
XCodeOrm
查
3975-5133-267
1452-3668-735
5230-8032-3241
1287-1670-240
3372-6264-954
2629-3825-836
1696-5363-716
使用有索引的列Guid排序
CYQOrm
EFOrm
MoonOrm
MySoftOrm
NHibernateOrm
PDFOrm
XCodeOrm
查
16-32-13
5-8-3
5967-14644-1639
2-5-1
7-127-2
1-17-0
1-9-0
经过测试,发现线程越多,越容易出现问题“超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。”导致访问很不稳定。
一个好的数据访问层应该是可以优雅的接受并处理大并发的访问,而不应该仅仅只盯住表面上的测试数据。
整个程序框架设计良好是更应该花更多心思考虑的。
从上面也可以看到,ORM性能其实并没有一般人想象的那么糟糕。
最后看看程序的代码是怎么样的。
项目目录
测试代码接口
public interface ITest
{
bool Insert();
bool Update(
string guid,
string content);
DataTable Select(
int count);
List<
string> GetGuidList(
int count);
bool Delete(
string guid);
}
View Code
ClownFish-SQL测试代码
public class ClownFishTest : DbContextHolderBase, ITest
{
static ClownFishTest()
{
DbContext.RegisterDbConnectionInfo(
"sqlserver",
"System.Data.SqlClient",
"@", Control.ConnectionStrings);
}
public void TruncateTable()
{
DbHelper.ExecuteNonQuery(SqlString.TruncateTable,
null, DbContext, CommandKind.SqlTextNoParams);
}
public bool Insert()
{
var parameter =
new { Guid = Guid.NewGuid(), Content =
string.Empty };
return (DbHelper.ExecuteNonQuery(SqlString.Insert, parameter, DbContext, CommandKind.SqlTextWithParams) >
0);
}
public bool Update(
string guid,
string content)
{
var parameter =
new { Guid = guid, Content = content };
return (DbHelper.ExecuteNonQuery(SqlString.Update, parameter, DbContext, CommandKind.SqlTextWithParams) >
0);
}
public DataTable Select(
int count)
{
return DbHelper.FillDataTable(
string.Format(SqlString.Select, count),
null, DbContext, CommandKind.SqlTextNoParams);
}
public List<
string> GetGuidList(
int count)
{
List<
string> result =
new List<
string>();
DataTable dtb = Select(count);
if (dtb ==
null || dtb.Rows.Count ==
0)
return result;
result.AddRange(
from DataRow row
in dtb.Rows
select row[
"Guid"].ToString());
return result;
}
public bool Delete(
string guid)
{
var parameter =
new { Guid = guid };
return (DbHelper.ExecuteNonQuery(SqlString.Delete, parameter, DbContext, CommandKind.SqlTextWithParams) >
0);
}
}
View Code
Moon-SQL测试代码
public class MoonTest : ITest
{
private readonly DB _dbHelper = DBFactory.
DefaultDB;
public bool Insert()
{
return (_dbHelper.ExecuteOneSql(
string.Format(SqlString.InsertFormat, Guid.NewGuid(),
string.Empty)) >
0);
}
public bool Update(
string guid,
string content)
{
return (_dbHelper.ExecuteOneSql(
string.Format(SqlString.UpdateFormat, guid, content)) >
0);
}
public DataTable Select(
int count)
{
return _dbHelper.GetDataTable(
string.Format(SqlString.Select, count));
}
public List<
string> GetGuidList(
int count)
{
List<
string> result =
new List<
string>();
DataTable dtb = Select(count);
if (dtb ==
null || dtb.Rows.Count ==
0)
return result;
result.AddRange(
from DataRow row
in dtb.Rows
select row[
"Guid"].ToString());
return result;
}
public bool Delete(
string guid)
{
return (_dbHelper.ExecuteOneSql(
string.Format( SqlString.DeleteFormat,guid)) >
0);
}
}
View Code
PDF-SQL测试代码
public class PdfTest : ITest
{
private readonly AdoHelper _dbHelper = MyDB.GetDBHelperByConnectionName(
"pdf");
public bool Insert()
{
IDataParameter[] parameters =
{
new SqlParameter(
"@Guid",SqlDbType.VarChar,
50){Value=Guid.NewGuid().ToString()},
new SqlParameter(
"@Content",SqlDbType.NVarChar,
500){Value=
string.Empty}
};
return (_dbHelper.ExecuteNonQuery(SqlString.Insert, CommandType.Text, parameters) >
0);
}
public bool Update(
string guid,
string content)
{
IDataParameter[] parameters =
{
new SqlParameter(
"@Guid",SqlDbType.VarChar,
50){Value=guid},
new SqlParameter(
"@Content",SqlDbType.NVarChar,
500){Value=content}
};
return (_dbHelper.ExecuteNonQuery(SqlString.Update, CommandType.Text, parameters) >
0);
}
public DataTable Select(
int count)
{
return _dbHelper.Execute
DataSet(
string.Format(SqlString.Select, count)).Tables[
0];
}
public List<
string> GetGuidList(
int count)
{
List<
string> result =
new List<
string>();
DataTable dtb = Select(count);
if (dtb ==
null || dtb.Rows.Count ==
0)
return result;
result.AddRange(
from DataRow row
in dtb.Rows
select row[
"Guid"].ToString());
return result;
}
public bool Delete(
string guid)
{
IDataParameter[] parameters =
{
new SqlParameter(
"@Guid",SqlDbType.VarChar,
50){Value=guid}
};
return (_dbHelper.ExecuteNonQuery(SqlString.Delete, CommandType.Text, parameters) >
0);
}
}
View Code
CYQ-ORM测试代码
public class CyqOrmTest : ITest
{
public bool Insert()
{
bool result;
using (MAction actiont =
new MAction(TableNames.Test))
{
actiont.Set(
"Guid", Guid.NewGuid());
result = actiont.Insert(InsertOp.None);
}
return result;
}
public bool Update(
string guid,
string content)
{
bool result;
using (MAction actiont =
new MAction(TableNames.Test))
{
actiont.Set(
"Content", content);
result = actiont.Update(
"Guid='" + guid +
"'");
}
return result;
}
public DataTable Select(
int count)
{
DataTable result;
using (MAction actiont =
new MAction(TableNames.Test))
{
result = actiont.Select(count,
"order by Guid").ToDataTable();
//actiont.Select(count, "order by RowId");
}
return result;
}
public List<
string> GetGuidList(
int count)
{
List<
string> result =
new List<
string>();
DataTable dtb = Select(count);
if (dtb ==
null || dtb.Rows.Count ==
0)
return result;
result.AddRange(
from DataRow row
in dtb.Rows
select row[
"Guid"].ToString());
return result;
}
public bool Delete(
string guid)
{
bool result;
using (MAction actiont =
new MAction(TableNames.Test))
{
result = actiont.Delete(
"Guid='" + guid +
"'");
}
return result;
}
}
View Code
EF-ORM测试代码
public class EFOrmTest : ITest
{
private readonly EFDbContext _dbContext;
//private static readonly EFDbContext _dbContext = new EFDbContext("Conn");
public EFOrmTest()
{
_dbContext =
new EFDbContext(
"Conn");
}
public bool Insert()
{
DbSet
model = _dbContext.Set();
model.Add(new TestModel { Guid = Guid.NewGuid().ToString(), EditDate = DateTime.Now });
_dbContext.SaveChanges();
return true;
}
public bool Update(string guid, string content)
{
var model = _dbContext.Set().Find(guid);
model.Content = content;
_dbContext.Entry(model).State = EntityState.Modified;
_dbContext.SaveChanges();
return true;
}
public DataTable Select(int count)
{
GetModelList(count);
return null;
}
public IList GetModelList(int count)
{
DbSet model = _dbContext.Set();
return model.OrderBy(o => o.Guid).Take(count).ToList();
}
public List<string> GetGuidList(int count)
{
List<string> result = new List<string>();
var list = GetModelList(count);
if (list == null || list.Count == 0)
return result;
result.AddRange(list.Select(o => o.Guid));
return result;
}
public bool Delete(string guid)
{
var model = _dbContext.Set().Find(guid);
_dbContext.Entry(model).State = EntityState.Deleted;
_dbContext.SaveChanges();
return true;
}
}
View Code
Moon-ORM测试代码
public class MoonOrmTest : ITest
{
public static void Init() { }
public bool Insert()
{
return DBFactory.Add(new MoonTestModel { Guid = Guid.NewGuid().ToString() }) != DBNull.Value;
}
public bool Update(string guid, string content)
{
var model = new MoonTestModel() { Content = content };
model.SetOnlyMark(TestTable.Guid.Equal(guid));
DBFactory.Update(model);
return true;
}
public DataTable Select(int count)
{
GetModelList(count);
return null;
}
public IList GetModelList(int count)
{
//没有找到更好的查询方式
return DBFactory.DefaultDB.GetPagedListDesc(1, count, TestTable.Guid, TestTable.Guid.NotEqual("''"));
}
public List<string> GetGuidList(int count)
{
List<string> result = new List<string>();
var list = GetModelList(count);
if (list == null || list.Count == 0)
return result;
result.AddRange(list.Select(moonTestModel => moonTestModel.Guid));
return result;
}
public bool Delete(string guid)
{
return DBFactory.DeleteWhen(TestTable.Guid.Equal(guid)) > 0;
}
}
View Code
MySoft-ORM测试代码
public class MySoftOrmTest : ITest
{
private static readonly DbSession DBSession = new DbSession(new MySoft.Data.SqlServer9.SqlServer9Provider(System.Configuration.ConfigurationManager.ConnectionStrings["Conn"].ConnectionString));
public bool Insert()
{
return DBSession.Insert(new[] { MySoftTestModel._.Guid }, new object[] { Guid.NewGuid().ToString() }) > 0;
}
public bool Update(string guid, string content)
{
return DBSession.Update(new[] { MySoftTestModel._.Content, MySoftTestModel._.EditDate }, new object[] { content, DateTime.Now }, MySoftTestModel._.Guid == guid) > 0;
}
public DataTable Select(int count)
{
GetModelList(count);
return null;
}
public IList GetModelList(int count)
{
return DBSession.From().OrderBy(MySoftTestModel._.Guid.Asc).GetTop(count).ToList();
}
public List<string> GetGuidList(int count)
{
List<string> result = new List<string>();
var list = GetModelList(count);
if (list == null || list.Count == 0)
return result;
result.AddRange(list.Select(o => o.Guid));
return result;
}
public bool Delete(string guid)
{
return DBSession.Delete(MySoftTestModel._.Guid == guid) > 0;
}
}
View Code
NHibernate-ORM测试代码
public class NHibernateOrmTest : ITest
{
private static readonly ISessionFactory SessionFactory = CreateSessionFactory();
static NHibernateOrmTest()
{
}
private static ISessionFactory CreateSessionFactory()
{
ISessionFactory sessionFactory;
try
{
sessionFactory = Fluently.Configure()
.Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2008
.ConnectionString(s => s.Server(".").Database("Test")
.TrustedConnection()))
.Mappings(m =>m.FluentMappings.Add())
.BuildSessionFactory();
}
catch (Exception ex)
{
throw;
}
return sessionFactory;
}
public bool Insert()
{
using (var session = SessionFactory.OpenSession())
{
var model = new TestModel { Guid = Guid.NewGuid().ToString() };
session.Save(model);
session.Flush();
}
return true;
}
public bool Update(string guid, string content)
{
using (var session = SessionFactory.OpenSession())
{
var model = new TestModel { Guid = guid, Content = content, EditDate = DateTime.Now };
session.Update(model);
session.Flush();
}
return true;
}
public DataTable Select(int count)
{
GetModelList(count);
return null;
}
public IList GetModelList(int count)
{
IList result;
using (var session = SessionFactory.OpenSession())
{
result = session.QueryOver().OrderBy(o=>o.Guid).Asc.Take(count).List();
}
return result;
}
public List<string> GetGuidList(int count)
{
List<string> result = new List<string>();
var list = GetModelList(count);
if (list == null || list.Count == 0)
return result;
result.AddRange(list.Select(o => o.Guid));
return result;
}
public bool Delete(string guid)
{
using (var session = SessionFactory.OpenSession())
{
var model = new TestModel { Guid = guid};
session.Delete(model);
session.Flush();
}
return true;
}
}
View Code
PDF-ORM测试代码
public class PdfOrmTest : ITest
{
private readonly AdoHelper _dbHelper = MyDB.GetDBHelperByConnectionName("pdf");
public bool Insert()
{
IDataParameter[] parameters =
{
new SqlParameter("@Guid",SqlDbType.VarChar,50){Value=Guid.NewGuid().ToString()},
new SqlParameter("@Content",SqlDbType.NVarChar,500){Value=string.Empty}
};
return (_dbHelper.ExecuteNonQuery(SqlString.Insert, CommandType.Text, parameters) > 0);
}
public bool Update(string guid, string content)
{
PdfTestModel model = new PdfTestModel
{
Guid = guid,
Content = content,
EditDate = DateTime.Now
};
OQL q = OQL.From(model).Update(model.Content, model.EditDate).Where(model.Guid).END;
return EntityQuery.ExecuteOql(q, _dbHelper) > 0;
}
public DataTable Select(int count)
{
GetModelList(count);
return null;
}
public List GetModelList(int count)
{
PdfTestModel model = new PdfTestModel();
OQL q = OQL.From(model).Limit(count).Select().OrderBy(model.Guid, "ASC").END;
return EntityQuery.QueryList(q);
}
public List<string> GetGuidList(int count)
{
List<string> result = new List<string>();
var list = GetModelList(count);
if (list == null || list.Count == 0)
return result;
result.AddRange(list.Select(o => o.Guid));
return result;
}
public bool Delete(string guid)
{
PdfTestModel model = new PdfTestModel { Guid = guid };
OQL q = OQL.From(model).Delete().Where(model.Guid).END;
return EntityQuery.ExecuteOql(q, _dbHelper) > 0;
}
}
View Code
XCode-ORM测试代码
public class XCodeOrmTest : ITest
{
static XCodeOrmTest()
{
XCode.DataAccessLayer.DAL.ShowSQL = false;
//XCode.DataAccessLayer.DAL.SQLPath = AppDomain.CurrentDomain.BaseDirectory;
}
public bool Insert()
{
var model = new XCodeTestModel();
model.Guid = Guid.NewGuid().ToString();
return model.Insert() > 0;
}
public bool Update(string guid, string content)
{
var model = XCodeTestModel.FindByGuid(guid);
model.Content = content;
model.EditDate = DateTime.Now;
return model.Update() > 0;
}
public DataTable Select(int count)
{
GetModelList(count);
return null;
}
public List GetModelList(int count)
{
return XCodeTestModel.Search(string.Empty, "Guid ASC", 0, count);
}
public List<string> GetGuidList(int count)
{
List<string> result = new List<string>();
var list = GetModelList(count);
if (list == null || list.Count == 0)
return result;
result.AddRange(list.Select(o => o.Guid));
return result;
}
public bool Delete(string guid)
{
//return XCodeTestModel.Delete(new[] { "Guid" }, new object[] { guid }) > 0;
return XCodeTestModel.FindByGuid(guid).Delete() > 0;
}
}
View Code
测试耗时监控
///
/// 执行指定查询的测试,并记录测试数据
///
/// 线程序号
/// 执行的查询
/// instance">执行测试的组件实体
private object TestWork(object index, Actionint> execute, ITest instance)
{
Stopwatch sw = new Stopwatch();
string threadName = string.Format("{0:D3}", index);
if (_showThreadWorkStatus)
UpdateMessage(string.Format("线程{0}开始时间:{1}", threadName, DateTime.Now));
sw.Start();
try
{execute(instance, (int) index);}
catch (Exception ex)
{UpdateMessage(string.Format("*线程{0} 执行错误,信息:{1}", threadName, ex.Message));}
sw.Stop();
if (_showThreadWorkStatus)
UpdateMessage(string.Format("*线程{0} *总耗时:{1} *当前时间:{2}", threadName, sw.ElapsedMilliseconds, DateTime.Now));
_waitWrite.WaitOne();
_waitWrite.Reset();
_workThreadCount--;
_totalElapsed += sw.ElapsedMilliseconds;
_workerInfo.Add(new Worker { Name = threadName, TotalElapsed = sw.ElapsedMilliseconds });
if (_workThreadCount == 0)
{
UpdateMessage(string.Format("全部线程总耗时:{0} *开始时间:{1} *结束时间:{2}", _totalElapsed, _beginTime, DateTime.Now));
UpdateChart();
EnableExecuteControl();
}
Application.DoEvents();
UpdateThreadCountBack();
_waitWrite.Set();
return 0;
}
View Code
测试完整逻辑代码 ,300多行,慎点。
public partial class FrmDbAccessTest : Form
{
private string _executeType = "Insert";//测试查询类型
private string _testLibClassPath = "DbAccessLibTest.Test.ClownFishTest";//测试组件类路径
private long _totalElapsed;//总耗时
private int _workThreadCount;//工作线程数
private int _threadCountCreated, _threadCountBack;
private int _executeCount;//执行查询次数(返回行数)
private bool _showThreadWorkStatus;
private Dictionary<int, List<string>> _guidList;//执行删除和修改时,预先取回的主键guid集合,按照每个线程序号分组分配
private List _workerInfo;//测试工作线程信息,主要用于图表数据显示
private ITest _testInstance;//用于准备执行删除、修改的guid集合
private DateTime _beginTime;//测试开始的时间
private readonly AutoResetEvent _waitWrite = new AutoResetEvent(true);//编辑总耗时等全局信息的信号灯
private CancellationTokenSource _taskCancelToken;
private readonly Assembly _self = Assembly.Load("数据访问组件测试");
public FrmDbAccessTest()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_workerInfo = new List();
chartMain.Series[0].XValueMember = "Name";
chartMain.Series[0].YValueMembers = "TotalElapsed";
chartMain.DataSource = _workerInfo;
}
///
/// 执行测试
///
private void btnExecute_Click(object sender, EventArgs e)
{
//初始化数据
_workThreadCount = (int)nuWorkThreadCount.Value;
_executeCount = (int)nuExecuteCount.Value;
_totalElapsed = 0;
_workerInfo = new List();
_testLibClassPath = "DbAccessLibTest.Test." + cmbTestLib.Text;
_testInstance = (ITest)_self.CreateInstance(_testLibClassPath);
_beginTime = DateTime.Now;
UpdateMessage(string.Format("测试开始时间:{0}", DateTime.Now));
UpdateMessage(string.Format(" 启动线程数:{0}", _workThreadCount));
UpdateMessage(string.Format(" 执行操作数:{0}", _executeCount));
btnExecute.Enabled = false;
nuThreadCountBack.Value = _threadCountBack = 0;
nuThreadCountCreated.Value = _threadCountCreated = 0;
_showThreadWorkStatus = ckbShowThreadStatus.Checked;
ckbShowThreadStatus.Enabled = false;
new Thread(TestMain).Start();
}
private void TestMain()
{
try
{
UpdateMessage(string.Format("数据准备开始:{0}", DateTime.Now));
Actionint> testExecute = GetExecuteUse();
UpdateMessage(string.Format("数据准备结束:{0}", DateTime.Now));
int createCount = _workThreadCount;
UpdateMessage(string.Format("开始创建线程:{0}", DateTime.Now));
_taskCancelToken = new CancellationTokenSource();
for (int index = 0; index < createCount; index++)
{
if (IsDisposed)
return;//防止重启程序时,仍然不断创建线程
if (rdbThreadPool.Checked)
UseThreadPool(index, testExecute);
else if (rdbThread.Checked)
UseThread(index, testExecute);
else
{
if (!UseTask(index, testExecute))
return;//如果已经重启程序,则跳出
}
Thread.Sleep(50);
UpdateThreadCountCreated();
}
UpdateMessage(string.Format("创建线程完毕:{0}", DateTime.Now));
}
catch (Exception ex)
{
UpdateMessage(ex.Message);
}
}
private void UseThreadPool(int index, Actionint> testExecute)
{
ThreadPool.QueueUserWorkItem(
threadIndex =>
TestWork(threadIndex, testExecute
, (ITest)_self.CreateInstance(_testLibClassPath)), index);
}
private void UseThread(int index, Actionint> testExecute)
{
new Thread(
threadIndex =>
TestWork(threadIndex, testExecute
, (ITest)_self.CreateInstance(_testLibClassPath)))
.Start(index);
}
private bool UseTask(int index, Actionint> testExecute)
{
var task = new Task<object>
(
threadIndex => TestWork(threadIndex, testExecute, (ITest)_self.CreateInstance(_testLibClassPath))
, index
, _taskCancelToken.Token
);
if (_taskCancelToken.IsCancellationRequested)
return false;
task.Start();
return true;
}
///
/// 执行指定查询的测试,并记录测试数据
///
/// 线程序号
/// 执行的查询
/// 执行测试的组件实体
private object TestWork(object index, Actionint> execute, ITest instance)
{
Stopwatch sw = new Stopwatch();
string threadName = string.Format("{0:D3}", index);
if (_showThreadWorkStatus)
UpdateMessage(string.Format("线程{0}开始时间:{1}", threadName, DateTime.Now));
sw.Start();
try
{execute(instance, (int) index);}
catch (Exception ex)
{UpdateMessage(string.Format("*线程{0} 执行错误,信息:{1}", threadName, ex.Message));}
sw.Stop();
if (_showThreadWorkStatus)
UpdateMessage(string.Format("*线程{0} *总耗时:{1} *当前时间:{2}", threadName, sw.ElapsedMilliseconds, DateTime.Now));
_waitWrite.WaitOne();
_waitWrite.Reset();
_workThreadCount--;
_totalElapsed += sw.ElapsedMilliseconds;
_workerInfo.Add(new Worker { Name = threadName, TotalElapsed = sw.ElapsedMilliseconds });
if (_workThreadCount == 0)
{
UpdateMessage(string.Format("全部线程总耗时:{0} *开始时间:{1} *结束时间:{2}", _totalElapsed, _beginTime, DateTime.Now));
UpdateChart();
EnableExecuteControl();
}
Application.DoEvents();
UpdateThreadCountBack();
_waitWrite.Set();
return 0;
}
#region 执行查询
private void ExecuteInsert(ITest instance, int threadIndex)
{
for (int i = 0; i < _executeCount; i++)
instance.Insert();
}
private void ExecuteUpdate(ITest instance, int threadIndex)
{
foreach (string guid in _guidList[threadIndex])
instance.Update(guid, string.Format("测试修改 **线程:{0}**组件:{1}**时间:{2}", threadIndex, instance.GetType(), DateTime.Now));
}
private void ExecuteDelete(ITest instance, int threadIndex)
{
foreach (string guid in _guidList[threadIndex])
instance.Delete(guid);
}
private void ExecuteSelect(ITest instance, int threadIndex)
{
instance.Select(_executeCount);
}
#endregion
///
/// 获取测试的操作,如果是删除和更新,则先准备数据
///
///
private Actionint> GetExecuteUse()
{
switch (_executeType)
{
case "Insert":
return ExecuteInsert;
case "Delete":
AssignGuid(); return ExecuteDelete;
case "Update":
AssignGuid(); return ExecuteUpdate;
case "Select":
return ExecuteSelect;
}
throw new Exception("程序异常:GetExecute");
}
///
/// 获取删除或者更新需要的guid集合,并分配给各个线程
///
private void AssignGuid()
{
var list = _testInstance.GetGuidList(_workThreadCount * _executeCount);
_guidList = new Dictionary<int, List<string>>(_workThreadCount);
for (int i = 0; i < _workThreadCount; i++)
_guidList.Add(i, new List<string>());
for (int i = 0; i < list.Count; i++)
{
int index = i % _workThreadCount;
_guidList[index].Add(list[i]);
}
}
///
/// 更新图表
///
private void UpdateChart()
{
if (IsDisposed)
return;
if (InvokeRequired)
BeginInvoke(new MethodInvoker(UpdateChart));
else
{
if (_workerInfo.Count > 10)
chartMain.Series[0].Label = string.Empty;
_workerInfo.Sort();
chartMain.DataSource = _workerInfo;
chartMain.ResetAutoValues();
}
}
///
/// 更新信息
///
///
private void UpdateMessage(string msg)
{
if (IsDisposed)
{
return;
}
if (InvokeRequired)
BeginInvoke(new MethodInvoker(() => UpdateMessage(msg)));
else
{
rtxtMessage.AppendText(msg + "\n");
rtxtMessage.Select(rtxtMessage.Text.Length - 1, 1);
rtxtMessage.ScrollToCaret();
}
}
///
/// 更新已创建线程数
///
private void UpdateThreadCountCreated()
{
if (IsDisposed)
return;
if (InvokeRequired)
BeginInvoke(new MethodInvoker(UpdateThreadCountCreated));
else
nuThreadCountCreated.Value = _threadCountCreated = (int)nuThreadCountCreated.Value + 1;
}
///
/// 更新返回线程数
///
private void UpdateThreadCountBack()
{
if (IsDisposed)
return;
if (InvokeRequired)
BeginInvoke(new MethodInvoker(UpdateThreadCountBack));
else
nuThreadCountBack.Value = _threadCountBack = (int)nuThreadCountBack.Value + 1;
}
///
/// 启用执行按钮
///
private void EnableExecuteControl()
{
if (IsDisposed)
return;
Invoke(new MethodInvoker(() =>
{
btnExecute.Enabled = true;
ckbShowThreadStatus.Enabled = true;
}));
}
private void rdbExecute_CheckedChanged(object sender, EventArgs e)
{
RadioButton rdb = sender as RadioButton;
if (rdb == null)
throw new Exception("程序异常:rdbExecute_CheckedChanged");
if (rdb.Checked)
_executeType = rdb.Text;
}
private void btnAnalysis_Click(object sender, EventArgs e)
{
//暂时没有实现
}
private void btnTruncateTable_Click(object sender, EventArgs e)
{
if (MessageBox.Show("确定要清空整个表吗", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
{
btnTruncateTable.Enabled = false;
new ClownFishTest().TruncateTable();
UpdateMessage("表已清空 - " + DateTime.Now);
btnTruncateTable.Enabled = true;
}
}
private void btnThreadInfo_Click(object sender, EventArgs e)
{
UpdateMessage(string.Format("线程数:{0}", _workThreadCount));
}
private void btnRestartForm_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
if (rdbTask.Checked)
_taskCancelToken.Cancel(true);
Close();
Dispose();
}
}
View Code
到底是选择ORM而不写Sql,还是 为了追求性能,而避开ORM,就看自己的情况来取舍了。
选择一个组件的时候,可以考虑这几方面:稳定性、性能、易用性、是否保持更新、是否有较好的文档手册、使用者社区怎么样、是否开源。
上面提供的组件测试代码也可以看到这些组件的代码风格,喜欢语法糖的不妨好好看看,到底更喜欢哪种风格。
综合考虑选择。
各组件地址
ClownFish:http://www.cnblogs.com/fish-li/ 【不开源】仅此一个是非ORM的。
CYQ:http://www.cnblogs.com/cyq1162/ 【逐版本开源】
EF: https://entityframework.codeplex.com/ 【开源】
Moon:http://www.cnblogs.com/humble/ 【不开源】
MySoft:http://www.cnblogs.com/maoyong/archive/2010/03/01/1675730.html 【逐版本开源】
NHibernate:http://nhforge.org/ 【开源】
PDF:http://home.cnblogs.com/u/bluedoctor/ 【开源】
XCode:http://xcode.codeplex.com/ 【开源】
希望更多的园友分享或开源自己所能知道的心爱的数据访问组件。
小广告:广州有工作机会的,烦请推荐。