PageRenderTime 72ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/Dapper.Tests.Performance/LegacyTests.cs

http://github.com/SamSaffron/dapper-dot-net
C# | 441 lines | 356 code | 56 blank | 29 comment | 13 complexity | 9d2c8c0404db75512cebda14a8fad240 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Data.SqlClient;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using Belgrade.SqlClient;
  8. using Dapper.Contrib.Extensions;
  9. using Dapper.Tests.Performance.Dashing;
  10. using Dapper.Tests.Performance.EntityFramework;
  11. using Dapper.Tests.Performance.EntityFrameworkCore;
  12. using Dapper.Tests.Performance.NHibernate;
  13. using Dashing;
  14. using DevExpress.Xpo;
  15. using DevExpress.Data.Filtering;
  16. using Massive;
  17. using Microsoft.EntityFrameworkCore;
  18. using NHibernate.Criterion;
  19. using ServiceStack.OrmLite;
  20. using ServiceStack.OrmLite.Dapper;
  21. using System.Configuration;
  22. using System.Threading.Tasks;
  23. #if NET4X
  24. using System.Data.Linq;
  25. using Dapper.Tests.Performance.Linq2Sql;
  26. using Dapper.Tests.Performance.Xpo;
  27. using NHibernate.Linq;
  28. using Susanoo;
  29. #endif
  30. namespace Dapper.Tests.Performance
  31. {
  32. public class LegacyTests
  33. {
  34. private class Test
  35. {
  36. public Test(Action<int> iteration, string name)
  37. {
  38. Iteration = iteration;
  39. Name = name;
  40. }
  41. public Test(Func<int, Task> iterationAsync, string name)
  42. {
  43. IterationAsync = iterationAsync;
  44. Name = name;
  45. }
  46. public Action<int> Iteration { get; set; }
  47. public Func<int, Task> IterationAsync { get; set; }
  48. public string Name { get; set; }
  49. public Stopwatch Watch { get; set; }
  50. }
  51. private class Tests : List<Test>
  52. {
  53. public void Add(Action<int> iteration, string name)
  54. {
  55. Add(new Test(iteration, name));
  56. }
  57. public void AsyncAdd(Func<int, Task> iterationAsync, string name)
  58. {
  59. Add(new Test(iterationAsync, name));
  60. }
  61. public async Task RunAsync(int iterations)
  62. {
  63. // warmup
  64. foreach (var test in this)
  65. {
  66. test.Iteration?.Invoke(iterations + 1);
  67. if (test.IterationAsync != null) await test.IterationAsync(iterations + 1).ConfigureAwait(false);
  68. test.Watch = new Stopwatch();
  69. test.Watch.Reset();
  70. }
  71. var rand = new Random();
  72. for (int i = 1; i <= iterations; i++)
  73. {
  74. foreach (var test in this.OrderBy(ignore => rand.Next()))
  75. {
  76. test.Watch.Start();
  77. test.Iteration?.Invoke(i);
  78. if (test.IterationAsync != null) await test.IterationAsync(i).ConfigureAwait(false);
  79. test.Watch.Stop();
  80. }
  81. }
  82. Console.WriteLine("|Time|Framework|");
  83. foreach (var test in this.OrderBy(t => t.Watch.ElapsedMilliseconds))
  84. {
  85. var ms = test.Watch.ElapsedMilliseconds.ToString();
  86. Console.Write("|");
  87. Console.Write(ms);
  88. Program.WriteColor("ms ".PadRight(8 - ms.Length), ConsoleColor.DarkGray);
  89. Console.Write("|");
  90. Console.Write(test.Name);
  91. Console.WriteLine("|");
  92. }
  93. }
  94. }
  95. public static string ConnectionString { get; } = ConfigurationManager.ConnectionStrings["Main"].ConnectionString;
  96. public static SqlConnection GetOpenConnection()
  97. {
  98. var connection = new SqlConnection(ConnectionString);
  99. connection.Open();
  100. return connection;
  101. }
  102. #if NET4X
  103. private static DataClassesDataContext GetL2SContext(SqlConnection connection) =>
  104. new DataClassesDataContext(connection);
  105. #endif
  106. private static void Try(Action action, string blame)
  107. {
  108. try
  109. {
  110. action();
  111. }
  112. catch (Exception ex)
  113. {
  114. Console.Error.WriteLine($"{blame}: {ex.Message}");
  115. }
  116. }
  117. public async Task RunAsync(int iterations)
  118. {
  119. using (var connection = GetOpenConnection())
  120. {
  121. #pragma warning disable IDE0017 // Simplify object initialization
  122. #pragma warning disable RCS1121 // Use [] instead of calling 'First'.
  123. var tests = new Tests();
  124. // Entity Framework Core
  125. Try(() =>
  126. {
  127. var entityContext = new EFCoreContext(ConnectionString);
  128. tests.Add(id => entityContext.Posts.First(p => p.Id == id), "Entity Framework Core");
  129. var entityContext2 = new EFCoreContext(ConnectionString);
  130. tests.Add(id => entityContext2.Posts.FromSql("select * from Posts where Id = {0}", id).First(), "Entity Framework Core: FromSql");
  131. var entityContext3 = new EFCoreContext(ConnectionString);
  132. tests.Add(id => entityContext3.Posts.AsNoTracking().First(p => p.Id == id), "Entity Framework Core: No Tracking");
  133. }, "Entity Framework Core");
  134. // Dapper
  135. Try(() =>
  136. {
  137. var mapperConnection = GetOpenConnection();
  138. tests.Add(id => mapperConnection.Query<Post>("select * from Posts where Id = @Id", new { Id = id }, buffered: true).First(), "Dapper: Query (buffered)");
  139. tests.Add(id => mapperConnection.Query<Post>("select * from Posts where Id = @Id", new { Id = id }, buffered: false).First(), "Dapper: Query (non-buffered)");
  140. tests.Add(id => mapperConnection.QueryFirstOrDefault<Post>("select * from Posts where Id = @Id", new { Id = id }), "Dapper: QueryFirstOrDefault");
  141. var mapperConnection2 = GetOpenConnection();
  142. tests.Add(id => mapperConnection2.Query("select * from Posts where Id = @Id", new { Id = id }, buffered: true).First(), "Dapper: Dynamic Query (buffered)");
  143. tests.Add(id => mapperConnection2.Query("select * from Posts where Id = @Id", new { Id = id }, buffered: false).First(), "Dapper: Dynamic Query (non-buffered)");
  144. tests.Add(id => mapperConnection2.QueryFirstOrDefault("select * from Posts where Id = @Id", new { Id = id }), "Dapper: Dynamic QueryFirstOrDefault");
  145. // dapper.contrib
  146. var mapperConnection3 = GetOpenConnection();
  147. tests.Add(id => mapperConnection3.Get<Post>(id), "Dapper.Contrib");
  148. }, "Dapper");
  149. // Massive
  150. Try(() =>
  151. {
  152. var massiveModel = new DynamicModel(ConnectionString);
  153. var massiveConnection = GetOpenConnection();
  154. tests.Add(id => massiveModel.Query("select * from Posts where Id = @0", massiveConnection, id).First(), "Massive: Dynamic ORM Query");
  155. }, "Massive");
  156. // PetaPoco
  157. Try(() =>
  158. {
  159. // PetaPoco test with all default options
  160. var petapoco = new PetaPoco.Database(ConnectionString, "System.Data.SqlClient");
  161. petapoco.OpenSharedConnection();
  162. tests.Add(id => petapoco.Fetch<Post>("SELECT * from Posts where Id=@0", id).First(), "PetaPoco: Normal");
  163. // PetaPoco with some "smart" functionality disabled
  164. var petapocoFast = new PetaPoco.Database(ConnectionString, "System.Data.SqlClient");
  165. petapocoFast.OpenSharedConnection();
  166. petapocoFast.EnableAutoSelect = false;
  167. petapocoFast.EnableNamedParams = false;
  168. petapocoFast.ForceDateTimesToUtc = false;
  169. tests.Add(id => petapocoFast.Fetch<Post>("SELECT * from Posts where Id=@0", id).First(), "PetaPoco: Fast");
  170. }, "PetaPoco");
  171. // NHibernate
  172. Try(() =>
  173. {
  174. var nhSession1 = NHibernateHelper.OpenSession();
  175. tests.Add(id => nhSession1.CreateSQLQuery("select * from Posts where Id = :id")
  176. .SetInt32("id", id)
  177. .List(), "NHibernate: SQL");
  178. var nhSession2 = NHibernateHelper.OpenSession();
  179. tests.Add(id => nhSession2.CreateQuery("from Post as p where p.Id = :id")
  180. .SetInt32("id", id)
  181. .List(), "NHibernate: HQL");
  182. var nhSession3 = NHibernateHelper.OpenSession();
  183. tests.Add(id => nhSession3.CreateCriteria<Post>()
  184. .Add(Restrictions.IdEq(id))
  185. .List(), "NHibernate: Criteria");
  186. var nhSession4 = NHibernateHelper.OpenSession();
  187. tests.Add(id => nhSession4
  188. .Query<Post>()
  189. .First(p => p.Id == id), "NHibernate: LINQ");
  190. var nhSession5 = NHibernateHelper.OpenSession();
  191. tests.Add(id => nhSession5.Get<Post>(id), "NHibernate: Session.Get");
  192. }, "NHibernate");
  193. // Belgrade
  194. Try(() =>
  195. {
  196. var query = new Belgrade.SqlClient.SqlDb.QueryMapper(ConnectionString);
  197. tests.AsyncAdd(id => query.Sql("SELECT TOP 1 * FROM Posts WHERE Id = @Id").Param("Id", id).Map(
  198. reader =>
  199. {
  200. var post = new Post();
  201. post.Id = reader.GetInt32(0);
  202. post.Text = reader.GetString(1);
  203. post.CreationDate = reader.GetDateTime(2);
  204. post.LastChangeDate = reader.GetDateTime(3);
  205. post.Counter1 = reader.IsDBNull(4) ? null : (int?)reader.GetInt32(4);
  206. post.Counter2 = reader.IsDBNull(5) ? null : (int?)reader.GetInt32(5);
  207. post.Counter3 = reader.IsDBNull(6) ? null : (int?)reader.GetInt32(6);
  208. post.Counter4 = reader.IsDBNull(7) ? null : (int?)reader.GetInt32(7);
  209. post.Counter5 = reader.IsDBNull(8) ? null : (int?)reader.GetInt32(8);
  210. post.Counter6 = reader.IsDBNull(9) ? null : (int?)reader.GetInt32(9);
  211. post.Counter7 = reader.IsDBNull(10) ? null : (int?)reader.GetInt32(10);
  212. post.Counter8 = reader.IsDBNull(11) ? null : (int?)reader.GetInt32(11);
  213. post.Counter9 = reader.IsDBNull(12) ? null : (int?)reader.GetInt32(12);
  214. }), "Belgrade Sql Client");
  215. }, "Belgrade Sql Client");
  216. //ServiceStack's OrmLite:
  217. Try(() =>
  218. {
  219. var dbFactory = new OrmLiteConnectionFactory(ConnectionString, SqlServerDialect.Provider);
  220. var db = dbFactory.Open();
  221. tests.Add(id => db.SingleById<Post>(id), "ServiceStack.OrmLite: SingleById");
  222. }, "ServiceStack.OrmLite");
  223. // Hand Coded
  224. Try(() =>
  225. {
  226. var postCommand = new SqlCommand()
  227. {
  228. Connection = connection,
  229. CommandText = @"select Id, [Text], [CreationDate], LastChangeDate,
  230. Counter1,Counter2,Counter3,Counter4,Counter5,Counter6,Counter7,Counter8,Counter9 from Posts where Id = @Id"
  231. };
  232. var idParam = postCommand.Parameters.Add("@Id", SqlDbType.Int);
  233. tests.Add(id =>
  234. {
  235. idParam.Value = id;
  236. using (var reader = postCommand.ExecuteReader())
  237. {
  238. reader.Read();
  239. var post = new Post();
  240. post.Id = reader.GetInt32(0);
  241. post.Text = reader.GetNullableString(1);
  242. post.CreationDate = reader.GetDateTime(2);
  243. post.LastChangeDate = reader.GetDateTime(3);
  244. post.Counter1 = reader.GetNullableValue<int>(4);
  245. post.Counter2 = reader.GetNullableValue<int>(5);
  246. post.Counter3 = reader.GetNullableValue<int>(6);
  247. post.Counter4 = reader.GetNullableValue<int>(7);
  248. post.Counter5 = reader.GetNullableValue<int>(8);
  249. post.Counter6 = reader.GetNullableValue<int>(9);
  250. post.Counter7 = reader.GetNullableValue<int>(10);
  251. post.Counter8 = reader.GetNullableValue<int>(11);
  252. post.Counter9 = reader.GetNullableValue<int>(12);
  253. }
  254. }, "Hand Coded");
  255. var table = new DataTable
  256. {
  257. Columns =
  258. {
  259. {"Id", typeof (int)},
  260. {"Text", typeof (string)},
  261. {"CreationDate", typeof (DateTime)},
  262. {"LastChangeDate", typeof (DateTime)},
  263. {"Counter1", typeof (int)},
  264. {"Counter2", typeof (int)},
  265. {"Counter3", typeof (int)},
  266. {"Counter4", typeof (int)},
  267. {"Counter5", typeof (int)},
  268. {"Counter6", typeof (int)},
  269. {"Counter7", typeof (int)},
  270. {"Counter8", typeof (int)},
  271. {"Counter9", typeof (int)},
  272. }
  273. };
  274. tests.Add(id =>
  275. {
  276. idParam.Value = id;
  277. object[] values = new object[13];
  278. using (var reader = postCommand.ExecuteReader())
  279. {
  280. reader.Read();
  281. reader.GetValues(values);
  282. table.Rows.Add(values);
  283. }
  284. }, "DataTable via IDataReader.GetValues");
  285. }, "Hand Coded");
  286. // DevExpress.XPO
  287. Try(() =>
  288. {
  289. IDataLayer dataLayer = XpoDefault.GetDataLayer(connection, DevExpress.Xpo.DB.AutoCreateOption.SchemaAlreadyExists);
  290. dataLayer.Dictionary.GetDataStoreSchema(typeof(Xpo.Post));
  291. UnitOfWork session = new UnitOfWork(dataLayer, dataLayer);
  292. session.IdentityMapBehavior = IdentityMapBehavior.Strong;
  293. session.TypesManager.EnsureIsTypedObjectValid();
  294. tests.Add(id => session.Query<Xpo.Post>().First(p => p.Id == id), "DevExpress.XPO: Query<T>");
  295. tests.Add(id => session.GetObjectByKey<Xpo.Post>(id, true), "DevExpress.XPO: GetObjectByKey<T>");
  296. tests.Add(id =>
  297. {
  298. CriteriaOperator findCriteria = new BinaryOperator()
  299. {
  300. OperatorType = BinaryOperatorType.Equal,
  301. LeftOperand = new OperandProperty("Id"),
  302. RightOperand = new ConstantValue(id)
  303. };
  304. session.FindObject<Xpo.Post>(findCriteria);
  305. }, "DevExpress.XPO: FindObject<T>");
  306. }, "DevExpress.XPO");
  307. // Entity Framework
  308. Try(() =>
  309. {
  310. var entityContext = new EFContext(connection);
  311. tests.Add(id => entityContext.Posts.First(p => p.Id == id), "Entity Framework");
  312. var entityContext2 = new EFContext(connection);
  313. tests.Add(id => entityContext2.Database.SqlQuery<Post>("select * from Posts where Id = {0}", id).First(), "Entity Framework: SqlQuery");
  314. var entityContext3 = new EFContext(connection);
  315. tests.Add(id => entityContext3.Posts.AsNoTracking().First(p => p.Id == id), "Entity Framework: No Tracking");
  316. }, "Entity Framework");
  317. #if NET4X
  318. // Linq2SQL
  319. Try(() =>
  320. {
  321. var l2scontext1 = GetL2SContext(connection);
  322. tests.Add(id => l2scontext1.Posts.First(p => p.Id == id), "Linq2Sql: Normal");
  323. var l2scontext2 = GetL2SContext(connection);
  324. var compiledGetPost = CompiledQuery.Compile((Linq2Sql.DataClassesDataContext ctx, int id) => ctx.Posts.First(p => p.Id == id));
  325. tests.Add(id => compiledGetPost(l2scontext2, id), "Linq2Sql: Compiled");
  326. var l2scontext3 = GetL2SContext(connection);
  327. tests.Add(id => l2scontext3.ExecuteQuery<Post>("select * from Posts where Id = {0}", id).First(), "Linq2Sql: ExecuteQuery");
  328. }, "LINQ-to-SQL");
  329. // Dashing
  330. Try(() =>
  331. {
  332. var config = new DashingConfiguration();
  333. var database = new SqlDatabase(config, ConnectionString);
  334. var session = database.BeginTransactionLessSession(GetOpenConnection());
  335. tests.Add(id => session.Get<Dashing.Post>(id), "Dashing Get");
  336. }, "Dashing");
  337. //Susanoo
  338. Try(() =>
  339. {
  340. var susanooDb = new DatabaseManager(connection);
  341. var susanooPreDefinedCommand =
  342. CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text)
  343. .DefineResults<Post>()
  344. .Realize();
  345. var susanooDynamicPreDefinedCommand =
  346. CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text)
  347. .DefineResults<dynamic>()
  348. .Realize();
  349. tests.Add(Id =>
  350. CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text)
  351. .DefineResults<Post>()
  352. .Realize()
  353. .Execute(susanooDb, new { Id }).First(), "Susanoo: Mapping Cache Retrieval");
  354. tests.Add(Id =>
  355. CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text)
  356. .DefineResults<dynamic>()
  357. .Realize()
  358. .Execute(susanooDb, new { Id }).First(), "Susanoo: Dynamic Mapping Cache Retrieval");
  359. tests.Add(Id => susanooDynamicPreDefinedCommand
  360. .Execute(susanooDb, new { Id }).First(), "Susanoo: Dynamic Mapping Static");
  361. tests.Add(Id => susanooPreDefinedCommand
  362. .Execute(susanooDb, new { Id }).First(), "Susanoo: Mapping Static");
  363. }, "Susanoo");
  364. #endif
  365. // Subsonic isn't maintained anymore - doesn't import correctly
  366. //Try(() =>
  367. // {
  368. // // Subsonic ActiveRecord
  369. // tests.Add(id => 3SubSonic.Post.SingleOrDefault(x => x.Id == id), "SubSonic ActiveRecord.SingleOrDefault");
  370. // // Subsonic coding horror
  371. // SubSonic.tempdbDB db = new SubSonic.tempdbDB();
  372. // tests.Add(id => new SubSonic.Query.CodingHorror(db.Provider, "select * from Posts where Id = @0", id).ExecuteTypedList<Post>(), "SubSonic Coding Horror");
  373. //}, "Subsonic");
  374. //// BLToolkit - doesn't import correctly in the new .csproj world
  375. //var db1 = new DbManager(GetOpenConnection());
  376. //tests.Add(id => db1.SetCommand("select * from Posts where Id = @id", db1.Parameter("id", id)).ExecuteList<Post>(), "BLToolkit");
  377. Console.WriteLine();
  378. Console.WriteLine("Running...");
  379. await tests.RunAsync(iterations).ConfigureAwait(false);
  380. #pragma warning restore RCS1121 // Use [] instead of calling 'First'.
  381. #pragma warning restore IDE0017 // Simplify object initialization
  382. }
  383. }
  384. }
  385. }