From ed239835c6ae84c090c5613fed9d154fe452c5d9 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Tue, 15 Jan 2019 18:36:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=8D=E5=B0=84+=E7=BC=93=E5=AD=98=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=EF=BC=8C=E6=8E=A5=E8=BF=91dapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MySqlAdoTest.cs | 37 +++++++++++++++ FreeSql.Tests.PerformanceTests/g.cs | 2 +- FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs | 3 ++ FreeSql/Internal/CommonExpression.cs | 11 +++-- .../SelectProvider/Select0Provider.cs | 15 +++++-- FreeSql/Internal/CommonUtils.cs | 1 + .../Internal/Model/ReadAnonymousTypeInfo.cs | 1 + FreeSql/Internal/Utils.cs | 45 ++++++++++++------- FreeSql/MySql/MySqlUtils.cs | 2 + FreeSql/Oracle/OracleUtils.cs | 1 + FreeSql/PostgreSQL/PostgreSQLUtils.cs | 1 + FreeSql/SqlServer/SqlServerUtils.cs | 1 + FreeSql/Sqlite/SqliteUtils.cs | 1 + 13 files changed, 98 insertions(+), 23 deletions(-) diff --git a/FreeSql.Tests.PerformanceTests/MySqlAdoTest.cs b/FreeSql.Tests.PerformanceTests/MySqlAdoTest.cs index 5e953aa0..b5091520 100644 --- a/FreeSql.Tests.PerformanceTests/MySqlAdoTest.cs +++ b/FreeSql.Tests.PerformanceTests/MySqlAdoTest.cs @@ -6,6 +6,8 @@ using Xunit; using Dapper; using System.Linq; using System.Collections.Generic; +using System.Threading.Tasks; +using System.Threading; namespace FreeSql.Tests.PerformanceTest { public class MySqlAdoTest { @@ -143,6 +145,41 @@ namespace FreeSql.Tests.PerformanceTest { sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*"); } + [Fact] + public void ToListLimit10() { + var sb = new StringBuilder(); + var time = new Stopwatch(); + + time.Restart(); + var dplist1Count = 0; + var p1 = Parallel.For(1, 50, b => { + List dplist1 = new List(); + for (var a = 0; a < 1000; a++) { + using (var conn = g.mysql.Ado.MasterPool.Get()) { + dplist1.AddRange(Dapper.SqlMapper.Query(conn.Value, "select * from song limit 50").ToList()); + } + } + Interlocked.Exchange(ref dplist1Count, dplist1.Count); + }); + while (p1.IsCompleted == false) ; + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1Count}; ORM: Dapper"); + + + time.Restart(); + var t3Count = 0; + var p3 = Parallel.For(1, 50, b => { + List t3 = new List(); + for (var a = 0; a < 1000; a++) { + t3.AddRange(g.mysql.Select().Limit(50).ToList()); + } + Interlocked.Exchange(ref t3Count, t3.Count); + }); + while (p3.IsCompleted == false) ; + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3Count}; ORM: FreeSql*"); + } + [Table(Name = "song")] class xxx { public int Id { get; set; } diff --git a/FreeSql.Tests.PerformanceTests/g.cs b/FreeSql.Tests.PerformanceTests/g.cs index f1cafbb0..76990132 100644 --- a/FreeSql.Tests.PerformanceTests/g.cs +++ b/FreeSql.Tests.PerformanceTests/g.cs @@ -7,7 +7,7 @@ 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") + .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=100") .UseLogger(new LoggerFactory().CreateLogger("FreeSql.MySql")) .UseAutoSyncStructure(false) .Build(); diff --git a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs index dd77d193..ed0ee7f2 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs @@ -34,6 +34,9 @@ namespace FreeSql.Tests.MySql { [Fact] public void ToList() { + var t0 = select.Limit(50).ToList(); + + var t1 = g.mysql.Select().Where("").Where(a => a.Id > 0).Skip(100).Limit(200).ToSql(); var t2 = g.mysql.Select().As("b").Where("").Where(a => a.Id > 0).Skip(100).Limit(200).ToSql(); diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index 1093abdb..73a6d9e7 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -58,7 +58,9 @@ namespace FreeSql.Internal { parent.Consturctor = map.First().Table.Table.Type.GetConstructor(new Type[0]); parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties; for (var idx = 0; idx < map.Count; idx++) { - var child = new ReadAnonymousTypeInfo { CsName = map[idx].Column.CsName, DbField = $"{map[idx].Table.Alias}.{_common.QuoteSqlName(map[idx].Column.Attribute.Name)}" }; + var child = new ReadAnonymousTypeInfo { + Property = map.First().Table.Table.Type.GetProperty(map[idx].Column.CsName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance), + CsName = map[idx].Column.CsName, DbField = $"{map[idx].Table.Alias}.{_common.QuoteSqlName(map[idx].Column.Attribute.Name)}" }; field.Append(", ").Append(_common.QuoteReadColumn(map[idx].Column.CsType, child.DbField)); if (index >= 0) field.Append(" as").Append(++index); parent.Childs.Add(child); @@ -75,7 +77,9 @@ namespace FreeSql.Internal { parent.Consturctor = newExp.Type.GetConstructors()[0]; parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Arguments; for (var a = 0; a < newExp.Members.Count; a++) { - var child = new ReadAnonymousTypeInfo { CsName = newExp.Members[a].Name, CsType = newExp.Arguments[a].Type }; + var child = new ReadAnonymousTypeInfo { + Property = newExp.Type.GetProperty(newExp.Members[a].Name, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance), + CsName = newExp.Members[a].Name, CsType = newExp.Arguments[a].Type }; parent.Childs.Add(child); ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a], getSelectGroupingMapString); } @@ -98,7 +102,8 @@ namespace FreeSql.Internal { case ReadAnonymousTypeInfoConsturctorType.Properties: var ret = parent.Consturctor.Invoke(null); for (var b = 0; b < parent.Childs.Count; b++) { - Utils.FillPropertyValue(ret, parent.Childs[b].CsName, ReadAnonymous(parent.Childs[b], dr, ref index)); + var prop = parent.Childs[b].Property; + prop.SetValue(ret, Utils.GetDataReaderValue(prop.PropertyType, ReadAnonymous(parent.Childs[b], dr, ref index)), null); } return ret; } diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index da35408d..0d3f4d99 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -1,5 +1,6 @@ using FreeSql.Internal.Model; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.Data.Common; @@ -220,14 +221,18 @@ namespace FreeSql.Internal.CommonProvider { } protected (ReadAnonymousTypeInfo map, string field) GetAllField() { var type = typeof(T1); - var map = new ReadAnonymousTypeInfo { Consturctor = type.GetConstructor(new Type[0]), ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties }; + if (Utils._dicClassConstructor.TryGetValue(type, out var classInfo) == false) { + classInfo = new Utils._dicClassConstructorInfo { Constructor = type.GetConstructor(new Type[0]), Properties = type.GetProperties() }; + Utils._dicClassConstructor.TryAdd(type, classInfo); + } + var map = new ReadAnonymousTypeInfo { Consturctor = classInfo.Constructor, ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties }; var field = new StringBuilder(); var dicfield = new Dictionary(); var tb = _tables.First(); var index = 0; - var ps = typeof(T1).GetProperties(); + var ps = classInfo.Properties; foreach (var p in ps) { - var child = new ReadAnonymousTypeInfo { CsName = p.Name }; + var child = new ReadAnonymousTypeInfo { Property = p, CsName = p.Name }; if (tb.Table.ColumnsByCs.TryGetValue(p.Name, out var col)) { //普通字段 if (index > 0) field.Append(", "); var quoteName = _commonUtils.QuoteSqlName(col.Attribute.Name); @@ -248,7 +253,9 @@ namespace FreeSql.Internal.CommonProvider { ++index; if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index); else dicfield.Add(quoteName, true); - child.Childs.Add(new ReadAnonymousTypeInfo { CsName = col2.CsName }); + child.Childs.Add(new ReadAnonymousTypeInfo { + Property = tb2.Table.Type.GetProperty(col2.CsName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance), + CsName = col2.CsName }); } } map.Childs.Add(child); diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index 4adb5382..e952a711 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -20,6 +20,7 @@ namespace FreeSql.Internal { internal abstract string Mod(string left, string right, Type leftType, Type rightType); internal abstract string QuoteWriteParamter(Type type, string paramterName); internal abstract string QuoteReadColumn(Type type, string columnName); + internal abstract string DbName { get; } internal ICodeFirst CodeFirst { get; set; } internal TableInfo GetTableByEntity(Type entity) => Utils.GetTableByEntity(entity, this); diff --git a/FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs b/FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs index 743d3646..33c4cf53 100644 --- a/FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs +++ b/FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs @@ -5,6 +5,7 @@ using System.Text; namespace FreeSql.Internal.Model { class ReadAnonymousTypeInfo { + public PropertyInfo Property { get; set; } public string CsName { get; set; } public Type CsType { get; set; } public string DbField { get; set; } diff --git a/FreeSql/Internal/Utils.cs b/FreeSql/Internal/Utils.cs index 4563295b..dc1df814 100644 --- a/FreeSql/Internal/Utils.cs +++ b/FreeSql/Internal/Utils.cs @@ -21,7 +21,7 @@ namespace FreeSql.Internal { static ConcurrentDictionary _cacheGetTableByEntity = new ConcurrentDictionary(); internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) { if (entity.FullName.StartsWith("<>f__AnonymousType")) return null; - if (_cacheGetTableByEntity.TryGetValue($"{common.QuoteSqlName("db")}{entity.FullName}", out var trytb)) return trytb; //区分数据库类型缓存 + if (_cacheGetTableByEntity.TryGetValue($"{common.DbName}-{entity.FullName}", out var trytb)) return trytb; //区分数据库类型缓存 if (common.CodeFirst.GetDbInfo(entity) != null) return null; var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute; @@ -163,6 +163,16 @@ namespace FreeSql.Internal { { typeof(JObject).FullName, true }, { typeof(JArray).FullName, true }, }; + internal static ConcurrentDictionary _dicClassConstructor = new ConcurrentDictionary(); + internal static ConcurrentDictionary _dicTupleConstructor = new ConcurrentDictionary(); + internal class _dicClassConstructorInfo { + public ConstructorInfo Constructor { get; set; } + public PropertyInfo[] Properties { get; set; } + } + internal class _dicTupleConstructorInfo { + public ConstructorInfo Constructor { get; set; } + public Type[] Types { get; set; } + } internal static (object value, int dataIndex) ExecuteArrayRowReadClassOrTuple(Type type, Dictionary names, object[] row, int dataIndex = 0) { if (type.IsArray) return (GetDataReaderValue(type, row[dataIndex]), dataIndex + 1); var typeGeneric = type; @@ -173,17 +183,18 @@ namespace FreeSql.Internal { if (type.Namespace == "System" && (type.FullName == "System.String" || type.IsValueType)) { //值类型,或者元组 bool isTuple = type.Name.StartsWith("ValueTuple`"); if (isTuple) { - var fs = type.GetFields(); - var types = new Type[fs.Length]; - var parms = new object[fs.Length]; - for (int a = 0; a < fs.Length; a++) { - types[a] = fs[a].FieldType; - var read = ExecuteArrayRowReadClassOrTuple(types[a], names, row, dataIndex); + if (_dicTupleConstructor.TryGetValue(type, out var tupleInfo) == false) { + var types = type.GetFields().Select(a => a.FieldType).ToArray(); + tupleInfo = new _dicTupleConstructorInfo { Constructor = type.GetConstructor(types), Types = types }; + _dicTupleConstructor.AddOrUpdate(type, tupleInfo, (t2, c2) => tupleInfo); + } + var parms = new object[tupleInfo.Types.Length]; + for (int a = 0; a < parms.Length; a++) { + var read = ExecuteArrayRowReadClassOrTuple(tupleInfo.Types[a], names, row, dataIndex); if (read.dataIndex > dataIndex) dataIndex = read.dataIndex; parms[a] = read.value; } - var constructor = type.GetConstructor(types); - return (constructor?.Invoke(parms), dataIndex); + return (tupleInfo.Constructor?.Invoke(parms), dataIndex); } return (dataIndex >= row.Length || (row[dataIndex] ?? DBNull.Value) == DBNull.Value ? null : GetDataReaderValue(type, row[dataIndex]), dataIndex + 1); } @@ -195,14 +206,18 @@ namespace FreeSql.Internal { return (expando, names.Count); } //类注入属性 - var value = type.GetConstructor(new Type[0]).Invoke(new object[0]); - var ps = type.GetProperties(); - foreach(var p in ps) { + if (_dicClassConstructor.TryGetValue(type, out var classInfo)== false) { + classInfo = new _dicClassConstructorInfo { Constructor = type.GetConstructor(new Type[0]), Properties = type.GetProperties() }; + _dicClassConstructor.TryAdd(type, classInfo); + } + var value = classInfo.Constructor.Invoke(new object[0]); + foreach(var prop in classInfo.Properties) { var tryidx = dataIndex; - if (names != null && names.TryGetValue(p.Name, out tryidx) == false) continue; - var read = ExecuteArrayRowReadClassOrTuple(p.PropertyType, names, row, tryidx); + if (names != null && names.TryGetValue(prop.Name, out tryidx) == false) continue; + var read = ExecuteArrayRowReadClassOrTuple(prop.PropertyType, names, row, tryidx); if (read.dataIndex > dataIndex) dataIndex = read.dataIndex; - FillPropertyValue(value, p.Name, read.value); + prop.SetValue(value, GetDataReaderValue(prop.PropertyType, read.value), null); + //FillPropertyValue(value, p.Name, read.value); //p.SetValue(value, read.value); } return (value, dataIndex); diff --git a/FreeSql/MySql/MySqlUtils.cs b/FreeSql/MySql/MySqlUtils.cs index ac538e0f..df62c478 100644 --- a/FreeSql/MySql/MySqlUtils.cs +++ b/FreeSql/MySql/MySqlUtils.cs @@ -9,6 +9,7 @@ namespace FreeSql.MySql { class MySqlUtils : CommonUtils { IFreeSql _orm; + public MySqlUtils(IFreeSql orm) { _orm = orm; } @@ -72,5 +73,6 @@ namespace FreeSql.MySql { } return columnName; } + internal override string DbName => "MySql"; } } diff --git a/FreeSql/Oracle/OracleUtils.cs b/FreeSql/Oracle/OracleUtils.cs index e987f25c..9abd7a9c 100644 --- a/FreeSql/Oracle/OracleUtils.cs +++ b/FreeSql/Oracle/OracleUtils.cs @@ -48,5 +48,6 @@ namespace FreeSql.Oracle { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; + internal override string DbName => "Oracle"; } } diff --git a/FreeSql/PostgreSQL/PostgreSQLUtils.cs b/FreeSql/PostgreSQL/PostgreSQLUtils.cs index f9971dd0..18c55556 100644 --- a/FreeSql/PostgreSQL/PostgreSQLUtils.cs +++ b/FreeSql/PostgreSQL/PostgreSQLUtils.cs @@ -104,5 +104,6 @@ namespace FreeSql.PostgreSQL { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; + internal override string DbName => "PostgreSQL"; } } diff --git a/FreeSql/SqlServer/SqlServerUtils.cs b/FreeSql/SqlServer/SqlServerUtils.cs index aa824e9f..b68204ef 100644 --- a/FreeSql/SqlServer/SqlServerUtils.cs +++ b/FreeSql/SqlServer/SqlServerUtils.cs @@ -42,5 +42,6 @@ namespace FreeSql.SqlServer { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; + internal override string DbName => "SqlServer"; } } diff --git a/FreeSql/Sqlite/SqliteUtils.cs b/FreeSql/Sqlite/SqliteUtils.cs index 16c195d1..a9ff66d9 100644 --- a/FreeSql/Sqlite/SqliteUtils.cs +++ b/FreeSql/Sqlite/SqliteUtils.cs @@ -63,5 +63,6 @@ namespace FreeSql.Sqlite { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; + internal override string DbName => "Sqlite"; } }