Skip to content

Commit d42b2fc

Browse files
2881028810
authored andcommitted
- 增加 ExpressionCallAttribute 特性,实现表达式函数自定义解析;
1 parent 91f0bb9 commit d42b2fc

File tree

6 files changed

+266
-160
lines changed

6 files changed

+266
-160
lines changed

FreeSql.Tests/FreeSql.Tests/UnitTest2.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Linq.Expressions;
1111
using System.Threading.Tasks;
1212
using System.ComponentModel.DataAnnotations;
13+
using System.Threading;
1314

1415
namespace FreeSql.Tests
1516
{
@@ -167,6 +168,34 @@ public class UserLike
167168
[Fact]
168169
public void Test02()
169170
{
171+
g.mysql.Aop.ParseExpression = (s, e) =>
172+
{
173+
if (e.Expression.NodeType == ExpressionType.Call)
174+
{
175+
var callExp = e.Expression as MethodCallExpression;
176+
if (callExp.Object?.Type == typeof(DateTime) &&
177+
callExp.Method.Name == "ToString" &&
178+
callExp.Arguments.Count == 1 &&
179+
callExp.Arguments[0].Type == typeof(string) &&
180+
callExp.Arguments[0].NodeType == ExpressionType.Constant)
181+
{
182+
var format = (callExp.Arguments[0] as ConstantExpression)?.Value?.ToString();
183+
184+
if (string.IsNullOrEmpty(format) == false)
185+
{
186+
var tmp = e.FreeParse(callExp.Object);
187+
188+
switch (format)
189+
{
190+
case "yyyy-MM-dd HH:mm":
191+
tmp = $"date_format({tmp}, '%Y-%m-%d %H:%i')";
192+
break;
193+
}
194+
e.Result = tmp;
195+
}
196+
}
197+
}
198+
};
170199

171200

172201
var dbs = g.sqlserver.DbFirst.GetDatabases();
@@ -233,6 +262,21 @@ public void Test02()
233262
.IncludeMany(m => m.Permissions.Where(p => p.SysModuleId == m.Id),
234263
then => then.LeftJoin(p => p.Button.Id == p.SysModuleButtonId))
235264
.ToList();
265+
266+
267+
var sql = g.sqlite.Select<SysModule>()
268+
.ToSql(a => a.CreateTime.FormatDateTime("yyyy-MM-dd"));
269+
}
270+
}
271+
272+
[ExpressionCall]
273+
public static class DbFunc
274+
{
275+
static ThreadLocal<ExpressionCallContext> context = new ThreadLocal<ExpressionCallContext>();
276+
277+
public static string FormatDateTime(this DateTime that, string arg1)
278+
{
279+
return $"date_format({context.Value.Values["arg1"]})";
236280
}
237281
}
238282
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace FreeSql.DataAnnotations
6+
{
7+
/// <summary>
8+
/// 自定义表达式函数解析<para></para>
9+
/// 注意:请使用静态扩展类
10+
/// </summary>
11+
[AttributeUsage(AttributeTargets.Class)]
12+
public class ExpressionCallAttribute : Attribute
13+
{
14+
}
15+
16+
public class ExpressionCallContext
17+
{
18+
/// <summary>
19+
/// 数据库类型,可用于适配多种数据库环境
20+
/// </summary>
21+
public DataType DataType { get; set; }
22+
23+
/// <summary>
24+
/// 已解析的表达式中参数内容
25+
/// </summary>
26+
public Dictionary<string, string> Values { get; } = new Dictionary<string, string>();
27+
}
28+
}

FreeSql/Extensions/FreeSqlGlobalExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ public static partial class FreeSqlGlobalExtensions
4444
public static bool IsArrayOrList(this Type that) => that == null ? false : (that.IsArray || typeof(IList).IsAssignableFrom(that));
4545
public static Type NullableTypeOrThis(this Type that) => that?.IsNullableType() == true ? that.GetGenericArguments().First() : that;
4646
internal static string NotNullAndConcat(this string that, params object[] args) => string.IsNullOrEmpty(that) ? null : string.Concat(new object[] { that }.Concat(args));
47+
static ConcurrentDictionary<Type, ParameterInfo[]> _dicGetDefaultValueFirstConstructorsParameters = new ConcurrentDictionary<Type, ParameterInfo[]>();
48+
public static object CreateInstanceGetDefaultValue(this Type that)
49+
{
50+
if (that == null) return null;
51+
if (that == typeof(string)) return default(string);
52+
if (that.IsArray) return Array.CreateInstance(that, 0);
53+
var ctorParms = _dicGetDefaultValueFirstConstructorsParameters.GetOrAdd(that, tp => tp.GetConstructors().FirstOrDefault()?.GetParameters());
54+
if (ctorParms == null || ctorParms.Any() == false) return Activator.CreateInstance(that, null);
55+
return Activator.CreateInstance(that, ctorParms.Select(a => Activator.CreateInstance(a.ParameterType, null)).ToArray());
56+
}
4757

4858
static ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>> _dicGetPropertiesDictIgnoreCase = new ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>>();
4959
public static Dictionary<string, PropertyInfo> GetPropertiesDictIgnoreCase(this Type that) => that == null ? null : _dicGetPropertiesDictIgnoreCase.GetOrAdd(that, tp =>

0 commit comments

Comments
 (0)