From 62a095df8f8a7a9c0bc66a8f65ae7d182d059a78 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Fri, 13 Sep 2019 00:23:52 +0800 Subject: [PATCH] v0.9.13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加 FreeSql.Extensions.JsonMap 扩展包,实现快速将对象映射为json字符串的方法; - 优化 表达式解析未实现的错误提醒,如 $""; --- Examples/base_entity/Program.cs | 31 ++++++++++ Examples/base_entity/base_entity.csproj | 1 + .../BaseEntityReadOnly.cs | 2 +- .../FreeSql.Extensions.BaseEntity.csproj | 3 +- .../DataAnnotations/JsonMapAttribute.cs | 13 ++++ .../FreeSql.Extensions.JsonMap.csproj | 29 +++++++++ .../FreeSql.Extensions.JsonMap/JsonMapCore.cs | 58 ++++++++++++++++++ .../FreeSql.Extensions.JsonMap/readme.md | 23 +++++++ .../FreeSql.Extensions.LazyLoading.csproj | 3 +- FreeSql.DbContext/FreeSql.DbContext.csproj | 3 +- FreeSql.Repository/FreeSql.Repository.csproj | 3 +- FreeSql.Tests/FreeSql.Tests/UnitTest1.cs | 3 + FreeSql.sln | 15 +++++ FreeSql/DataAnnotations/ColumnAttribute.cs | 4 +- FreeSql/FreeSql.csproj | 3 +- FreeSql/FreeSql.xml | 4 +- FreeSql/Internal/CommonExpression.cs | 14 +++-- FreeSql/Internal/UtilsExpressionTree.cs | 12 ++-- .../FreeSql.Provider.MySql.csproj | 3 +- .../FreeSql.Provider.MySql/MySqlExpression.cs | 10 +-- .../FreeSql.Provider.MySql/MySqlProvider.cs | 4 +- .../FreeSql.Provider.MySqlConnector.csproj | 3 +- .../FreeSql.Provider.Oracle.csproj | 3 +- .../OracleExpression.cs | 10 +-- .../FreeSql.Provider.PostgreSQL.csproj | 3 +- .../PostgreSQLExpression.cs | 10 +-- .../PostgreSQLProvider.cs | 4 +- .../FreeSql.Provider.SqlServer.csproj | 3 +- .../SqlServerExpression.cs | 10 +-- .../FreeSql.Provider.Sqlite.csproj | 3 +- .../SqliteExpression.cs | 10 +-- logo.png | Bin 0 -> 9201 bytes readme.md | 2 + 33 files changed, 249 insertions(+), 53 deletions(-) create mode 100644 Extensions/FreeSql.Extensions.JsonMap/DataAnnotations/JsonMapAttribute.cs create mode 100644 Extensions/FreeSql.Extensions.JsonMap/FreeSql.Extensions.JsonMap.csproj create mode 100644 Extensions/FreeSql.Extensions.JsonMap/JsonMapCore.cs create mode 100644 Extensions/FreeSql.Extensions.JsonMap/readme.md create mode 100644 logo.png diff --git a/Examples/base_entity/Program.cs b/Examples/base_entity/Program.cs index d6868178..7312f114 100644 --- a/Examples/base_entity/Program.cs +++ b/Examples/base_entity/Program.cs @@ -1,17 +1,48 @@ using FreeSql; +using FreeSql.DataAnnotations; +using FreeSql.Extensions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; +using System.Linq.Expressions; using System.Threading.Tasks; namespace base_entity { class Program { + class TestConfig + { + public int clicks { get; set; } + public string title { get; set; } + } + [Table(Name = "sysconfig")] + public class S_SysConfig : BaseEntity> + { + [Column(IsPrimary = true)] + public string Name { get; set; } + + [JsonMap] + public T Config { get; set; } + } + static void Main(string[] args) { + #region 初始化 IFreeSql BaseEntity.Initialization(new FreeSql.FreeSqlBuilder() .UseAutoSyncStructure(true) + .UseNoneCommandParameter(true) .UseConnectionString(FreeSql.DataType.Sqlite, "data source=test.db;max pool size=5") + .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=2") .Build()); + #endregion + + BaseEntity.Orm.UseJsonMap(); + + new S_SysConfig { Name = "testkey11", Config = new TestConfig { clicks = 11, title = "testtitle11" } }.Save(); + new S_SysConfig { Name = "testkey22", Config = new TestConfig { clicks = 22, title = "testtitle22" } }.Save(); + new S_SysConfig { Name = "testkey33", Config = new TestConfig { clicks = 33, title = "testtitle33" } }.Save(); + var testconfigs11 = S_SysConfig.Select.ToList(); Task.Run(async () => { diff --git a/Examples/base_entity/base_entity.csproj b/Examples/base_entity/base_entity.csproj index c05b214a..f177d568 100644 --- a/Examples/base_entity/base_entity.csproj +++ b/Examples/base_entity/base_entity.csproj @@ -15,6 +15,7 @@ + diff --git a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs index 365ae1b0..e7e82ce5 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs +++ b/Extensions/FreeSql.Extensions.BaseEntity/BaseEntityReadOnly.cs @@ -43,7 +43,7 @@ namespace FreeSql /// 创建时间 /// [Column(Position = -4)] - public DateTime CreateTime { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; /// /// 更新时间 /// diff --git a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj index d6d6f617..d293c21e 100644 --- a/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj +++ b/Extensions/FreeSql.Extensions.BaseEntity/FreeSql.Extensions.BaseEntity.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 0.9.12 + 0.9.15 true YeXiangQin BaseEntity 是一种极简单的 CodeFirst 开发方式,特别对单表或多表CRUD,利用继承节省了每个实体类的重复属性(创建时间、ID等字段),软件删除等功能,进行 crud 操作时不必时常考虑仓储的使用. @@ -12,6 +12,7 @@ MIT FreeSql;ORM;BaseEntity $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/Extensions/FreeSql.Extensions.JsonMap/DataAnnotations/JsonMapAttribute.cs b/Extensions/FreeSql.Extensions.JsonMap/DataAnnotations/JsonMapAttribute.cs new file mode 100644 index 00000000..44f5d8a1 --- /dev/null +++ b/Extensions/FreeSql.Extensions.JsonMap/DataAnnotations/JsonMapAttribute.cs @@ -0,0 +1,13 @@ +using System; +using System.Linq; + +namespace FreeSql.DataAnnotations +{ + + /// + /// 当实体类属性为【对象】时,以JSON形式映射存储 + /// + public class JsonMapAttribute : Attribute + { + } +} diff --git a/Extensions/FreeSql.Extensions.JsonMap/FreeSql.Extensions.JsonMap.csproj b/Extensions/FreeSql.Extensions.JsonMap/FreeSql.Extensions.JsonMap.csproj new file mode 100644 index 00000000..a4e16229 --- /dev/null +++ b/Extensions/FreeSql.Extensions.JsonMap/FreeSql.Extensions.JsonMap.csproj @@ -0,0 +1,29 @@ + + + + netstandard2.0;net45 + 0.9.15 + true + YeXiangQin + FreeSql 扩展包,可实现实体类属性为对象时,以JSON形式映射存储. + https://github.com/2881099/FreeSql + https://github.com/2881099/FreeSql + git + MIT + FreeSql;ORM + $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png + $(AssemblyName) + true + true + + + + + + + + + + + diff --git a/Extensions/FreeSql.Extensions.JsonMap/JsonMapCore.cs b/Extensions/FreeSql.Extensions.JsonMap/JsonMapCore.cs new file mode 100644 index 00000000..e5593617 --- /dev/null +++ b/Extensions/FreeSql.Extensions.JsonMap/JsonMapCore.cs @@ -0,0 +1,58 @@ +using FreeSql.DataAnnotations; +using Newtonsoft.Json; +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; + +namespace FreeSql.Extensions +{ + public static class JsonMapCore + { + static bool _isAoped = false; + static object _isAopedLock = new object(); + static ConcurrentDictionary _dicTypes = new ConcurrentDictionary(); + static MethodInfo MethodJsonConvertDeserializeObject = typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) }); + static MethodInfo MethodJsonConvertSerializeObject = typeof(JsonConvert).GetMethod("SerializeObject", new[] { typeof(object) }); + + /// + /// 当实体类属性为【对象】时,并且标记特性 [JsonMap] 时,该属性将以JSON形式映射存储 + /// + /// + public static void UseJsonMap(this IFreeSql that) + { + if (_isAoped == false) + lock(_isAopedLock) + if (_isAoped == false) + { + _isAoped = true; + + FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type) => + { + if (_dicTypes.ContainsKey(type)) return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(valueExp, typeof(string)), Expression.Constant(type)), type)); + return null; + }); + + that.Aop.ConfigEntityProperty += new EventHandler((s, e) => + { + if (e.Property.GetCustomAttribute(false) != null) + { + e.ModifyResult.MapType = typeof(string); + if (_dicTypes.TryAdd(e.Property.PropertyType, true)) + { + FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionObjectToStringIfThenElse.Add((LabelTarget returnTarget, Expression valueExp, Expression elseExp, Type type) => + { + return Expression.IfThenElse( + Expression.TypeEqual(valueExp, e.Property.PropertyType), + Expression.Return(returnTarget, Expression.Call(MethodJsonConvertSerializeObject, Expression.Convert(valueExp, typeof(object))), typeof(object)), + elseExp); + }); + } + } + }); + } + } + } +} diff --git a/Extensions/FreeSql.Extensions.JsonMap/readme.md b/Extensions/FreeSql.Extensions.JsonMap/readme.md new file mode 100644 index 00000000..96906cd8 --- /dev/null +++ b/Extensions/FreeSql.Extensions.JsonMap/readme.md @@ -0,0 +1,23 @@ +FreeSql 扩展包,将值对象映射成 typeof(string),安装扩展包: + +> dotnet add package FreeSql.Extensions.JsonMap + +```csharp +fsql.UseJsonMap(); //开启功能 + +class TestConfig +{ + public int clicks { get; set; } + public string title { get; set; } +} + +[Table(Name = "sysconfig")] +public class S_SysConfig +{ + [Column(IsPrimary = true)] + public string Name { get; set; } + + [JsonMap] + public T Config { get; set; } +} +``` \ No newline at end of file diff --git a/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj b/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj index 1a3a82c9..c1d3828d 100644 --- a/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj +++ b/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql 扩展包,可实现【延时加载】属性. @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/FreeSql.DbContext/FreeSql.DbContext.csproj b/FreeSql.DbContext/FreeSql.DbContext.csproj index f979a9ec..1b6415fb 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.csproj +++ b/FreeSql.DbContext/FreeSql.DbContext.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. @@ -11,6 +11,7 @@ git MIT $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/FreeSql.Repository/FreeSql.Repository.csproj b/FreeSql.Repository/FreeSql.Repository.csproj index 1f98a00a..290e6b23 100644 --- a/FreeSql.Repository/FreeSql.Repository.csproj +++ b/FreeSql.Repository/FreeSql.Repository.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 YeXiangQin FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table. https://github.com/2881099/FreeSql/wiki/Repository @@ -11,6 +11,7 @@ git MIT $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/FreeSql.Tests/FreeSql.Tests/UnitTest1.cs b/FreeSql.Tests/FreeSql.Tests/UnitTest1.cs index 4f95cf07..edf94e73 100644 --- a/FreeSql.Tests/FreeSql.Tests/UnitTest1.cs +++ b/FreeSql.Tests/FreeSql.Tests/UnitTest1.cs @@ -406,6 +406,9 @@ namespace FreeSql.Tests [Fact] public void Test1() { + + var testssargs1 = "10100"; + var testformatsql1 = g.mysql.Select().Where(a => a.NamespaceName == $"1_{10100}").ToSql(); var testorderbysql = g.mysql.Select().OrderByDescending(a => a.OptionsEntity04 + (a.score ?? 0)).ToSql(); var testincludeMemberssql1 = g.sqlite.Select().Where(a => a.Templates.Title == "1").ToList(); diff --git a/FreeSql.sln b/FreeSql.sln index 78427fa6..42ee6d17 100644 --- a/FreeSql.sln +++ b/FreeSql.sln @@ -58,6 +58,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "base_entity", "Examples\bas EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.BaseEntity", "Extensions\FreeSql.Extensions.BaseEntity\FreeSql.Extensions.BaseEntity.csproj", "{FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.JsonMap", "Extensions\FreeSql.Extensions.JsonMap\FreeSql.Extensions.JsonMap.csproj", "{3043DEF1-85DF-47AD-8D5D-327270794356}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -332,6 +334,18 @@ Global {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|x64.Build.0 = Release|Any CPU {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|x86.ActiveCfg = Release|Any CPU {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6}.Release|x86.Build.0 = Release|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Debug|x64.ActiveCfg = Debug|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Debug|x64.Build.0 = Debug|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Debug|x86.ActiveCfg = Debug|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Debug|x86.Build.0 = Debug|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Release|Any CPU.Build.0 = Release|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Release|x64.ActiveCfg = Release|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Release|x64.Build.0 = Release|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Release|x86.ActiveCfg = Release|Any CPU + {3043DEF1-85DF-47AD-8D5D-327270794356}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -352,6 +366,7 @@ Global {4C0973CB-BD49-4A5B-A6FE-EE0594BDD513} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} {D3A1869C-A8DE-46D0-8587-89EBBE3E4DD0} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} {FE0CB06E-493F-4CE8-B2D7-BF48CA8015C6} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} + {3043DEF1-85DF-47AD-8D5D-327270794356} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98} diff --git a/FreeSql/DataAnnotations/ColumnAttribute.cs b/FreeSql/DataAnnotations/ColumnAttribute.cs index 21dede2d..9040fe96 100644 --- a/FreeSql/DataAnnotations/ColumnAttribute.cs +++ b/FreeSql/DataAnnotations/ColumnAttribute.cs @@ -77,7 +77,9 @@ namespace FreeSql.DataAnnotations public object DbDefautValue { get; internal set; } /// - /// 类型映射,比如:可将 enum 属性映射成 typeof(string) + /// 类型映射,除了可做基本的类型映射外,特别介绍的功能: + /// 1、将 enum 属性映射成 typeof(string) + /// 2、将 对象 属性映射成 typeof(string),请安装扩展包 FreeSql.Extensions.JsonMap /// public Type MapType { get; set; } diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index d5f2185f..ac1c46e2 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 82735bc2..3ce7b5a3 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -57,7 +57,9 @@ - 类型映射,比如:可将 enum 属性映射成 typeof(string) + 类型映射,除了可做基本的类型映射外,特别介绍的功能: + 1、将 enum 属性映射成 typeof(string) + 2、将 对象 属性映射成 typeof(string),请安装扩展包 FreeSql.Extensions.JsonMap diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index deada8a9..4fc329c6 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -535,14 +535,16 @@ namespace FreeSql.Internal tsc.mapType = null; var exp3 = exp as MethodCallExpression; var callType = exp3.Object?.Type ?? exp3.Method.DeclaringType; + string other3Exp = null; switch (callType.FullName) { - case "System.String": return ExpressionLambdaToSqlCallString(exp3, tsc); - case "System.Math": return ExpressionLambdaToSqlCallMath(exp3, tsc); - case "System.DateTime": return ExpressionLambdaToSqlCallDateTime(exp3, tsc); - case "System.TimeSpan": return ExpressionLambdaToSqlCallTimeSpan(exp3, tsc); - case "System.Convert": return ExpressionLambdaToSqlCallConvert(exp3, tsc); + case "System.String": other3Exp = ExpressionLambdaToSqlCallString(exp3, tsc); break; + case "System.Math": other3Exp = ExpressionLambdaToSqlCallMath(exp3, tsc); break; + case "System.DateTime": other3Exp = ExpressionLambdaToSqlCallDateTime(exp3, tsc); break; + case "System.TimeSpan": other3Exp = ExpressionLambdaToSqlCallTimeSpan(exp3, tsc); break; + case "System.Convert": other3Exp = ExpressionLambdaToSqlCallConvert(exp3, tsc); break; } + if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp; if (exp3.Method.Name == "Equals" && exp3.Object != null && exp3.Arguments.Count > 0) return ExpressionBinary("=", exp3.Object, exp3.Arguments[0], tsc); if (callType.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) @@ -849,7 +851,7 @@ namespace FreeSql.Internal // } //} - var other3Exp = ExpressionLambdaToSqlOther(exp3, tsc); + other3Exp = ExpressionLambdaToSqlOther(exp3, tsc); if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp; if (exp3.IsParameter() == false) return formatSql(Expression.Lambda(exp3).Compile().DynamicInvoke(), tsc.mapType); throw new Exception($"未实现函数表达式 {exp3} 解析"); diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index f3dbe11d..6b7824c1 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -1466,7 +1466,8 @@ namespace FreeSql.Internal static PropertyInfo PropertyDateTimeTicks = typeof(DateTime).GetProperty("Ticks", BindingFlags.Instance | BindingFlags.Public); static ConstructorInfo CtorDateTimeOffsetArgsTicks = typeof(DateTimeOffset).GetConstructor(new[] { typeof(long), typeof(TimeSpan) }); - public static ConcurrentBag> GetDataReaderValueBlockExpressionSwitchTypeFullName = new ConcurrentBag>(); + public static ConcurrentBag> GetDataReaderValueBlockExpressionSwitchTypeFullName = new ConcurrentBag>(); + public static ConcurrentBag> GetDataReaderValueBlockExpressionObjectToStringIfThenElse = new ConcurrentBag>(); public static Expression GetDataReaderValueBlockExpression(Type type, Expression value) { var returnTarget = Expression.Label(typeof(object)); @@ -1728,11 +1729,14 @@ namespace FreeSql.Internal default: foreach (var switchFunc in GetDataReaderValueBlockExpressionSwitchTypeFullName) { - var switchFuncRet = switchFunc(returnTarget, valueExp, type.FullName); + var switchFuncRet = switchFunc(returnTarget, valueExp, type); if (switchFuncRet != null) return switchFuncRet; } break; } + Expression callToStringExp = Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodToString, valueExp), typeof(object))); + foreach (var toStringFunc in GetDataReaderValueBlockExpressionObjectToStringIfThenElse) + callToStringExp = toStringFunc(returnTarget, valueExp, callToStringExp, type); Expression switchExp = null; if (tryparseExp != null) switchExp = Expression.Switch( @@ -1753,12 +1757,12 @@ namespace FreeSql.Internal Expression.SwitchCase(Expression.Return(returnTarget, Expression.Call(MethodConvertChangeType, valueExp, Expression.Constant(type, typeof(Type)))), Expression.Constant(type)) ); else if (type == typeof(string)) - switchExp = Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodToString, valueExp), typeof(object))); + switchExp = callToStringExp; else switchExp = Expression.Return(returnTarget, Expression.Call(MethodConvertChangeType, valueExp, Expression.Constant(type, typeof(Type)))); var defaultRetExp = type == typeof(string) ? - Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodToString, valueExp), typeof(object))) : + callToStringExp : Expression.Return(returnTarget, Expression.Call(MethodConvertChangeType, valueExp, Expression.Constant(type, typeof(Type)))); return Expression.IfThenElse( diff --git a/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj b/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj index 0a95f0f2..83500b51 100644 --- a/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj +++ b/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj @@ -2,7 +2,7 @@ netstandard2.0;net452 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql 数据库实现,基于 MySql 5.6 @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/Providers/FreeSql.Provider.MySql/MySqlExpression.cs b/Providers/FreeSql.Provider.MySql/MySqlExpression.cs index d9fb104f..d74aa632 100644 --- a/Providers/FreeSql.Provider.MySql/MySqlExpression.cs +++ b/Providers/FreeSql.Provider.MySql/MySqlExpression.cs @@ -310,7 +310,7 @@ namespace FreeSql.MySql case "Equals": return $"({left} = {getExp(exp.Arguments[0])})"; } } - throw new Exception($"MySqlExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc) { @@ -338,7 +338,7 @@ namespace FreeSql.MySql case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; case "Truncate": return $"truncate({getExp(exp.Arguments[0])}, 0)"; } - throw new Exception($"MySqlExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc) { @@ -388,7 +388,7 @@ namespace FreeSql.MySql case "ToString": return $"date_format({left}, '%Y-%m-%d %H:%i:%s.%f')"; } } - throw new Exception($"MySqlExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc) { @@ -424,7 +424,7 @@ namespace FreeSql.MySql case "ToString": return $"cast({left} as char)"; } } - throw new Exception($"MySqlExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc) { @@ -450,7 +450,7 @@ namespace FreeSql.MySql case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as unsigned)"; } } - throw new Exception($"MySqlExpression 未实现函数表达式 {exp} 解析"); + return null; } } } diff --git a/Providers/FreeSql.Provider.MySql/MySqlProvider.cs b/Providers/FreeSql.Provider.MySql/MySqlProvider.cs index f53a0ebe..c62decfe 100644 --- a/Providers/FreeSql.Provider.MySql/MySqlProvider.cs +++ b/Providers/FreeSql.Provider.MySql/MySqlProvider.cs @@ -22,9 +22,9 @@ namespace FreeSql.MySql Utils.dicExecuteArrayRowReadClassOrTuple[typeof(MygisMultiPolygon)] = true; var MethodMygisGeometryParse = typeof(MygisGeometry).GetMethod("Parse", new[] { typeof(string) }); - Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, string typeFullName) => + Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type) => { - switch (typeFullName) + switch (type.FullName) { case "MygisPoint": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisPoint))); case "MygisLineString": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisLineString))); diff --git a/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj b/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj index 27540c59..7b1b720a 100644 --- a/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj +++ b/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql 数据库实现,基于 MySql 5.6 @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj b/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj index e33a267d..a5e45c58 100644 --- a/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj +++ b/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql 数据库实现,基于 Oracle 11 @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/Providers/FreeSql.Provider.Oracle/OracleExpression.cs b/Providers/FreeSql.Provider.Oracle/OracleExpression.cs index 3bf13ec4..d516f0a2 100644 --- a/Providers/FreeSql.Provider.Oracle/OracleExpression.cs +++ b/Providers/FreeSql.Provider.Oracle/OracleExpression.cs @@ -310,7 +310,7 @@ namespace FreeSql.Oracle case "Equals": return $"({left} = {getExp(exp.Arguments[0])})"; } } - throw new Exception($"OracleExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc) { @@ -340,7 +340,7 @@ namespace FreeSql.Oracle //case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 0)"; } - throw new Exception($"OracleExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc) { @@ -390,7 +390,7 @@ namespace FreeSql.Oracle case "ToString": return $"to_char({left},'YYYY-MM-DD HH24:MI:SS.FF6')"; } } - throw new Exception($"OracleExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc) { @@ -426,7 +426,7 @@ namespace FreeSql.Oracle case "ToString": return $"to_char({left})"; } } - throw new Exception($"OracleExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc) { @@ -452,7 +452,7 @@ namespace FreeSql.Oracle case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as number)"; } } - throw new Exception($"OracleExpression 未实现函数表达式 {exp} 解析"); + return null; } } } diff --git a/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj b/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj index 14a68880..31cadc17 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj +++ b/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql 数据库实现,基于 PostgreSQL 9.5 @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLExpression.cs b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLExpression.cs index e0bc9eab..e6c3bd02 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLExpression.cs +++ b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLExpression.cs @@ -421,7 +421,7 @@ namespace FreeSql.PostgreSQL case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::varchar)"; } } - throw new Exception($"PostgreSQLExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc) { @@ -449,7 +449,7 @@ namespace FreeSql.PostgreSQL case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 0)"; } - throw new Exception($"PostgreSQLExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc) { @@ -499,7 +499,7 @@ namespace FreeSql.PostgreSQL case "ToString": return $"to_char({left}, 'YYYY-MM-DD HH24:MI:SS.US')"; } } - throw new Exception($"PostgreSQLExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc) { @@ -535,7 +535,7 @@ namespace FreeSql.PostgreSQL case "ToString": return $"({left})::varchar"; } } - throw new Exception($"PostgreSQLExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc) { @@ -561,7 +561,7 @@ namespace FreeSql.PostgreSQL case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8"; } } - throw new Exception($"PostgreSQLExpression 未实现函数表达式 {exp} 解析"); + return null; } } } diff --git a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs index b3f949aa..21627b10 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs +++ b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs @@ -51,9 +51,9 @@ namespace FreeSql.PostgreSQL var MethodJTokenParse = typeof(JToken).GetMethod("Parse", new[] { typeof(string) }); var MethodJObjectParse = typeof(JObject).GetMethod("Parse", new[] { typeof(string) }); var MethodJArrayParse = typeof(JArray).GetMethod("Parse", new[] { typeof(string) }); - Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, string typeFullName) => + Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type) => { - switch (typeFullName) + switch (type.FullName) { case "Newtonsoft.Json.Linq.JToken": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJTokenParse, Expression.Convert(valueExp, typeof(string))), typeof(JToken))); case "Newtonsoft.Json.Linq.JObject": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJObjectParse, Expression.Convert(valueExp, typeof(string))), typeof(JObject))); diff --git a/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj b/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj index 94c9b532..a2067ff8 100644 --- a/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj +++ b/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj @@ -2,7 +2,7 @@ netstandard2.0;net451 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql 数据库实现,基于 SqlServer 2005+,并根据版本适配分页方法:row_number 或 offset fetch next @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/Providers/FreeSql.Provider.SqlServer/SqlServerExpression.cs b/Providers/FreeSql.Provider.SqlServer/SqlServerExpression.cs index 24fd1a33..28b7cc4e 100644 --- a/Providers/FreeSql.Provider.SqlServer/SqlServerExpression.cs +++ b/Providers/FreeSql.Provider.SqlServer/SqlServerExpression.cs @@ -292,7 +292,7 @@ namespace FreeSql.SqlServer case "Equals": return $"({left} = {getExp(exp.Arguments[0])})"; } } - throw new Exception($"SqlServerExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc) { @@ -320,7 +320,7 @@ namespace FreeSql.SqlServer case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; case "Truncate": return $"floor({getExp(exp.Arguments[0])})"; } - throw new Exception($"SqlServerExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc) { @@ -370,7 +370,7 @@ namespace FreeSql.SqlServer case "ToString": return $"convert(varchar, {left}, 121)"; } } - throw new Exception($"SqlServerExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc) { @@ -406,7 +406,7 @@ namespace FreeSql.SqlServer case "ToString": return $"cast({left} as varchar)"; } } - throw new Exception($"SqlServerExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc) { @@ -432,7 +432,7 @@ namespace FreeSql.SqlServer case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as bigint)"; } } - throw new Exception($"SqlServerExpression 未实现函数表达式 {exp} 解析"); + return null; } } } diff --git a/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj b/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj index e22d4e66..1bcc27a7 100644 --- a/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj +++ b/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.9.12 + 0.9.15 true YeXiangQin FreeSql 数据库实现,基于 Sqlite 3.0 @@ -12,6 +12,7 @@ MIT FreeSql;ORM $(AssemblyName) + https://github.com/2881099/FreeSql/blob/master/logo.png $(AssemblyName) true true diff --git a/Providers/FreeSql.Provider.Sqlite/SqliteExpression.cs b/Providers/FreeSql.Provider.Sqlite/SqliteExpression.cs index b3f1541e..cca89bb8 100644 --- a/Providers/FreeSql.Provider.Sqlite/SqliteExpression.cs +++ b/Providers/FreeSql.Provider.Sqlite/SqliteExpression.cs @@ -314,7 +314,7 @@ namespace FreeSql.Sqlite case "Equals": return $"({left} = {getExp(exp.Arguments[0])})"; } } - throw new Exception($"SqliteExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc) { @@ -342,7 +342,7 @@ namespace FreeSql.Sqlite case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; //case "Truncate": return $"truncate({getExp(exp.Arguments[0])}, 0)"; } - throw new Exception($"SqliteExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc) { @@ -392,7 +392,7 @@ namespace FreeSql.Sqlite case "ToString": return $"strftime('%Y-%m-%d %H:%M.%f',{left})"; } } - throw new Exception($"SqliteExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc) { @@ -428,7 +428,7 @@ namespace FreeSql.Sqlite case "ToString": return $"cast({left} as character)"; } } - throw new Exception($"SqliteExpression 未实现函数表达式 {exp} 解析"); + return null; } public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc) { @@ -454,7 +454,7 @@ namespace FreeSql.Sqlite case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as decimal(21,0))"; } } - throw new Exception($"SqliteExpression 未实现函数表达式 {exp} 解析"); + return null; } } } diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d7e56b8dcd31aae9455d7441d9a9a33e380ea96a GIT binary patch literal 9201 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