This commit is contained in:
28810 2019-01-14 14:15:46 +08:00
parent b92f480cda
commit ec6d482321
16 changed files with 212 additions and 44 deletions

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="MySql.Data" Version="8.0.13" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FreeSql\FreeSql.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,91 @@
using FreeSql.DataAnnotations;
using System;
using System.Diagnostics;
using System.Text;
using Xunit;
using Dapper;
using System.Linq;
using System.Collections.Generic;
namespace FreeSql.Tests.PerformanceTest {
public class MySqlAdoTest {
[Fact]
public void Query() {
var sb = new StringBuilder();
var time = new Stopwatch();
time.Restart();
List<xxx> dplist1 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist1 = Dapper.SqlMapper.Query<xxx>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper");
time.Restart();
List<(int, string, string)> dplist2 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist2 = Dapper.SqlMapper.Query<(int, string, string)>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Tuple Counts: {dplist2.Count}; ORM: Dapper");
time.Restart();
List<dynamic> dplist3 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist3 = Dapper.SqlMapper.Query<dynamic>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Dynamic Counts: {dplist3.Count}; ORM: Dapper");
time.Restart();
var t3 = g.mysql.Ado.Query<xxx>("select * from song");
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {t3.Count}; ORM: FreeSql*");
time.Restart();
var t4 = g.mysql.Ado.Query<(int, string, string)>("select * from song");
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Tuple Counts: {t4.Count}; ORM: FreeSql*");
time.Restart();
var t5 = g.mysql.Ado.Query<dynamic>("select * from song");
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Dynamic Counts: {t3.Count}; ORM: FreeSql*");
}
[Fact]
public void ToList() {
var sb = new StringBuilder();
var time = new Stopwatch();
time.Restart();
List<xxx> dplist1 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist1 = Dapper.SqlMapper.Query<xxx>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper");
time.Restart();
var t3 = g.mysql.Select<xxx>().ToList();
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*");
}
[Table(Name = "song")]
class xxx {
public int Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public DateTime Create_time { get; set; }
public bool Is_deleted { get; set; }
}
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
public class g {
public static IFreeSql mysql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
.UseLogger(new LoggerFactory().CreateLogger("FreeSql.MySql"))
.UseAutoSyncStructure(false)
.Build();
//public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder()
// .UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=cms;Pooling=true;Max Pool Size=10")
// .UseLogger(new LoggerFactory().CreateLogger("FreeSql.SqlServer"))
// .UseAutoSyncStructure(false)
// .Build();
//public static IFreeSql pgsql = new FreeSql.FreeSqlBuilder()
// .UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=10")
// .UseLogger(new LoggerFactory().CreateLogger("FreeSql.PostgreSQL"))
// .UseAutoSyncStructure(false)
// .UseSyncStructureToLower(true)
// .Build();
//public static IFreeSql oracle = new FreeSql.FreeSqlBuilder()
// .UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=10")
// .UseLogger(new LoggerFactory().CreateLogger("FreeSql.Oracle"))
// .UseAutoSyncStructure(false)
// .Build();
//public static IFreeSql sqlite = new FreeSql.FreeSqlBuilder()
// .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10")
// .UseLogger(new LoggerFactory().CreateLogger("FreeSql.Sqlite"))
// .UseAutoSyncStructure(false)
// .Build();
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
@ -15,5 +15,5 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FreeSql\FreeSql.csproj" /> <ProjectReference Include="..\FreeSql\FreeSql.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -14,11 +14,6 @@ namespace FreeSql.Tests.MySql {
var t2 = g.mysql.Ado.SlavePools.Count; var t2 = g.mysql.Ado.SlavePools.Count;
} }
[Fact]
public void IsTracePerformance() {
Assert.True(g.mysql.Ado.IsTracePerformance);
}
[Fact] [Fact]
public void ExecuteReader() { public void ExecuteReader() {

View File

@ -14,11 +14,6 @@ namespace FreeSql.Tests.Oracle {
var t2 = g.oracle.Ado.SlavePools.Count; var t2 = g.oracle.Ado.SlavePools.Count;
} }
[Fact]
public void IsTracePerformance() {
Assert.True(g.oracle.Ado.IsTracePerformance);
}
[Fact] [Fact]
public void ExecuteReader() { public void ExecuteReader() {

View File

@ -14,11 +14,6 @@ namespace FreeSql.Tests.PostgreSQL {
var t2 = g.pgsql.Ado.SlavePools.Count; var t2 = g.pgsql.Ado.SlavePools.Count;
} }
[Fact]
public void IsTracePerformance() {
Assert.True(g.pgsql.Ado.IsTracePerformance);
}
[Fact] [Fact]
public void ExecuteReader() { public void ExecuteReader() {

View File

@ -14,11 +14,6 @@ namespace FreeSql.Tests.SqlServer {
var t2 = g.sqlserver.Ado.SlavePools.Count; var t2 = g.sqlserver.Ado.SlavePools.Count;
} }
[Fact]
public void IsTracePerformance() {
Assert.True(g.sqlserver.Ado.IsTracePerformance);
}
[Fact] [Fact]
public void ExecuteReader() { public void ExecuteReader() {

View File

@ -13,12 +13,6 @@ namespace FreeSql.Tests.Sqlite {
public void SlavePools() { public void SlavePools() {
var t2 = g.sqlite.Ado.SlavePools.Count; var t2 = g.sqlite.Ado.SlavePools.Count;
} }
[Fact]
public void IsTracePerformance() {
Assert.True(g.sqlite.Ado.IsTracePerformance);
}
[Fact] [Fact]
public void ExecuteReader() { public void ExecuteReader() {

View File

@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{C6A74E2A-6
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xxx", "..\..\新建文件夹 (9)\xxx.csproj", "{6DC39740-0B26-4029-AB75-D436A7F666A2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xxx", "..\..\新建文件夹 (9)\xxx.csproj", "{6DC39740-0B26-4029-AB75-D436A7F666A2}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeSql.Tests.PerformanceTests", "FreeSql.Tests.PerformanceTests\FreeSql.Tests.PerformanceTests.csproj", "{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -71,6 +73,18 @@ Global
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x64.Build.0 = Release|Any CPU {6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x64.Build.0 = Release|Any CPU
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x86.ActiveCfg = Release|Any CPU {6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x86.ActiveCfg = Release|Any CPU
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x86.Build.0 = Release|Any CPU {6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x86.Build.0 = Release|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Debug|x64.ActiveCfg = Debug|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Debug|x64.Build.0 = Debug|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Debug|x86.ActiveCfg = Debug|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Debug|x86.Build.0 = Debug|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Release|Any CPU.Build.0 = Release|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Release|x64.ActiveCfg = Release|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Release|x64.Build.0 = Release|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Release|x86.ActiveCfg = Release|Any CPU
{446D9CBE-BFE4-4FB3-ADFD-4C1C5EA1B6EE}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -2,10 +2,10 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Version>0.0.5</Version> <Version>0.0.6</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>YeXiangQin</Authors> <Authors>YeXiangQin</Authors>
<Description>打造 .NETCore 最方便的 ORMDbFirst 与 CodeFirst 混合使用,提供从实体同步数据库,或者从数据库生成实体代码,支持 MySql/SqlServer/PostgreSQL 数据库。</Description> <Description>打造 .NETCore 最方便的 ORMDbFirst 与 CodeFirst 混合使用,提供从实体同步数据库,或者从数据库生成实体代码,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite 数据库。</Description>
<PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl> <PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl>
<PackageTags>FreeSql ORM</PackageTags> <PackageTags>FreeSql ORM</PackageTags>
</PropertyGroup> </PropertyGroup>
@ -24,6 +24,7 @@
<PackageReference Include="SafeObjectPool" Version="1.0.12" /> <PackageReference Include="SafeObjectPool" Version="1.0.12" />
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" /> <PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.109.2" /> <PackageReference Include="System.Data.SQLite.Core" Version="1.0.109.2" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -78,7 +78,7 @@ namespace FreeSql {
/// 监视数据库命令对象 /// 监视数据库命令对象
/// </summary> /// </summary>
/// <param name="executing">执行前</param> /// <param name="executing">执行前</param>
/// <param name="executed">执行后</param> /// <param name="executed">执行后,可监视执行性能</param>
/// <returns></returns> /// <returns></returns>
public FreeSqlBuilder UseMonitorCommand(Action<DbCommand> executing, Action<DbCommand, string> executed = null) { public FreeSqlBuilder UseMonitorCommand(Action<DbCommand> executing, Action<DbCommand, string> executed = null) {
_aopCommandExecuting = executing; _aopCommandExecuting = executing;

View File

@ -18,9 +18,13 @@ namespace FreeSql {
/// </summary> /// </summary>
List<ObjectPool<DbConnection>> SlavePools { get; } List<ObjectPool<DbConnection>> SlavePools { get; }
/// <summary> /// <summary>
/// 是否跟踪记录SQL执行性能日志 /// 监视数据库命令对象(执行前,调试)
/// </summary> /// </summary>
bool IsTracePerformance { get; set; } Action<DbCommand> AopCommandExecuting { get; set; }
/// <summary>
/// 监视数据库命令对象(执行后,用于监视执行性能)
/// </summary>
Action<DbCommand, string> AopCommandExecuted { get; set; }
#region #region
/// <summary> /// <summary>

View File

@ -4,6 +4,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Data.Common; using System.Data.Common;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -13,10 +14,10 @@ namespace FreeSql.Internal.CommonProvider {
protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex); protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex);
protected abstract DbCommand CreateCommand(); protected abstract DbCommand CreateCommand();
protected abstract DbParameter[] GetDbParamtersByObject(string sql, object obj); protected abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
internal Action<DbCommand> AopCommandExecuting = null; public Action<DbCommand> AopCommandExecuting { get; set; }
internal Action<DbCommand, string> AopCommandExecuted = null; public Action<DbCommand, string> AopCommandExecuted { get; set; }
public bool IsTracePerformance { get; set; } = string.Compare(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), "Development", true) == 0; protected bool IsTracePerformance => AopCommandExecuted != null;
public ObjectPool<DbConnection> MasterPool { get; protected set; } public ObjectPool<DbConnection> MasterPool { get; protected set; }
public List<ObjectPool<DbConnection>> SlavePools { get; } = new List<ObjectPool<DbConnection>>(); public List<ObjectPool<DbConnection>> SlavePools { get; } = new List<ObjectPool<DbConnection>>();
@ -64,19 +65,15 @@ namespace FreeSql.Internal.CommonProvider {
public List<T> Query<T>(string sql, object parms = null) => Query<T>(CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); public List<T> Query<T>(string sql, object parms = null) => Query<T>(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
public List<T> Query<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) { public List<T> Query<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase); var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
var ds = new List<object[]>(); var ret = new List<T>();
ExecuteReader(dr => { ExecuteReader(dr => {
if (names.Any() == false) if (names.Any() == false)
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a); for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
object[] values = new object[dr.FieldCount]; object[] values = new object[dr.FieldCount];
dr.GetValues(values); dr.GetValues(values);
ds.Add(values); var read = Utils.ExecuteArrayRowReadClassOrTuple(typeof(T), names, values, 0);
ret.Add(read.value == null ? default(T) : (T)read.value);
}, cmdType, cmdText, cmdParms); }, cmdType, cmdText, cmdParms);
var ret = new List<T>();
foreach (var row in ds) {
var read = Utils.ExecuteArrayRowReadClassOrTuple(typeof(T), names, row);
ret.Add(read.value == null ? default(T) : (T) read.value);
}
return ret; return ret;
} }
public void ExecuteReader(Action<DbDataReader> readerHander, string sql, object parms = null) => ExecuteReader(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); public void ExecuteReader(Action<DbDataReader> readerHander, string sql, object parms = null) => ExecuteReader(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms));

View File

@ -191,7 +191,7 @@ namespace FreeSql.Internal {
dynamic expando = new System.Dynamic.ExpandoObject(); //动态类型字段 可读可写 dynamic expando = new System.Dynamic.ExpandoObject(); //动态类型字段 可读可写
var expandodic = (IDictionary<string, object>)expando; var expandodic = (IDictionary<string, object>)expando;
foreach (var name in names) foreach (var name in names)
expandodic[Utils.GetCsName(name.Key)] = row[name.Value]; expandodic.Add(name.Key, row[name.Value]);
return (expando, names.Count); return (expando, names.Count);
} }
//类注入属性 //类注入属性

View File

@ -158,6 +158,33 @@ List<dynamic> t8 = fsql.Ado.Query<dynamic>("select * from song");
``` ```
> 更多资料:[《Select查询数据》](Docs/select.md) > 更多资料:[《Select查询数据》](Docs/select.md)
## 性能测试
### FreeSql ToList & Dapper Query
Elapsed: 00:00:00.9666720; Query Entity Counts: 131072; ORM: Dapper
Elapsed: 00:00:01.4215325; ToList Entity Counts: 131072; ORM: FreeSql*
### FreeSql Query & Dapper Query
Elapsed: 00:00:00.9728656; Query Entity Counts: 131072; ORM: Dapper
Elapsed: 00:00:00.4484073; Query Tuple Counts: 131072; ORM: Dapper
Elapsed: 00:00:00.6580620; Query Dynamic Counts: 131072; ORM: Dapper
Elapsed: 00:00:02.6804199; Query Entity Counts: 131072; ORM: FreeSql*
Elapsed: 00:00:01.4161527; Query Tuple Counts: 131072; ORM: FreeSql*
Elapsed: 00:00:00.9965082; Query Dynamic Counts: 131072; ORM: FreeSql*
[查看测试代码](/2881099/FreeSql/tree/master/FreeSql.Tests.PerformanceTests/MySqlAdoTest.cs)
FreeSql 目前使用的反射+缓存,比不过 Dapper Emit 性能。
# Part2 添加 # Part2 添加
```csharp ```csharp
var items = new List<Topic>(); var items = new List<Topic>();