dotnetcore / FreeSql

🦄 .NET aot orm, C# orm, VB.NET orm, Mysql orm, Postgresql orm, SqlServer orm, Oracle orm, Sqlite orm, Firebird orm, 达梦 orm, 人大金仓 orm, 神通 orm, 翰高 orm, 南大通用 orm, 虚谷 orm, 国产 orm, Clickhouse orm, QuestDB orm, MsAccess orm.
http://freesql.net
MIT License
4.08k stars 849 forks source link

关于自定义表达式函数的建议 #1810

Open zhaxg opened 3 months ago

zhaxg commented 3 months ago

Feature 特性

实现类似linq2db的表达式函数设计模式:
            LinqToDB.Common.Configuration.Linq.AllowMultipleQuery = true;
            LinqToDB.DataProvider.Oracle.OracleTools.UseAlternativeBulkCopy = AlternativeBulkCopy.InsertInto;

            //注册自定义sql函数
            LinqToDB.Linq.Expressions.MapMember<string, string, bool>((a, b) => a.IsGt(b), (x, y) => x.CompareTo(y) > 0);
            LinqToDB.Linq.Expressions.MapMember<string, string, bool>((a, b) => a.IsGe(b), (x, y) => x.CompareTo(y) >= 0);
            LinqToDB.Linq.Expressions.MapMember<string, string, bool>((a, b) => a.IsLt(b), (x, y) => x.CompareTo(y) < 0);
            LinqToDB.Linq.Expressions.MapMember<string, string, bool>((a, b) => a.IsLe(b), (x, y) => x.CompareTo(y) <= 0);
            LinqToDB.Linq.Expressions.MapMember<object, object[], bool>((a, b) => a.IsIn(b), (x, y) => y.Contains(x));
            LinqToDB.Linq.Expressions.MapMember<object, object[], bool>((a, b) => a.IsLooseIn(b), (x, y) => y.Length == 0 || y.Contains(x));

            LinqToDB.Linq.Expressions.MapMember<string, bool>(a => a.IsNullOrEmpty(), a => a == null || a.Length == 0);
            LinqToDB.Linq.Expressions.MapMember<string, bool>(a => a.IsNotNullOrEmpty(), a => a != null && a.Length > 0);
            LinqToDB.Linq.Expressions.MapMember<string, bool>(a => a.IsTrue(), x => new[] { "y", "true", "yes", "1" }.Contains(x.ToLower()));

            LinqToDB.Linq.Expressions.MapMember<IComparable, IComparable, IComparable, bool>((x, low, high) => x.Between(low, high), (x, low, high) => Sql.Between(x, low, high));

简要描述原因

大多数函数都是c#正常使用的函数,不需要再设计一个[ExpressionCall],而且两个静态的扩展函数会冲突

使用场景

// c# code
2881099 commented 3 months ago

两个静态方法冲突是什么意思?

zhaxg commented 3 months ago

[ExpressionCall] public static class DbFunc { //必要定义 static + ThreadLocal static ThreadLocal context = new ThreadLocal();

public static DateTime FormatDateTime(this DateTime that, string arg1) { var up = context.Value; if (up.DataType == FreeSql.DataType.Sqlite) //重写内容 up.Result = $"date_format({up.ParsedContent["that"]}, {up.ParsedContent["arg1"]})"; return that; } } 这个方法就是一个很直接的静态扩展方法,没有办法确保不会被团队的人误用了,如果是string.isnullorempty这种,我在正常的逻辑里面可以使用,那么在freesql的查询表达式应该是一致的逻辑,而不是两套逻辑,另外一个isnullorempty扩展方法是特定给freesql去解析sql的

zhaxg commented 3 months ago

你可以看看与了解一下linq2db的自定义函数如何实现的

2881099 commented 3 months ago

怎么会被乱用呢,乱用不应该是团队规范的问题么

d4ilys commented 3 months ago

扩展方法的命名和表达式函数表示的 SQL 字符串没有啥关联 命名可以有个规范 比如 FormatDateTimeForSqlFun 另外FreeSql经历了这么多版本的迭代肯定不会去修改 自定义解析 的逻辑

pjy612 commented 3 months ago

如果楼主就觉得 linq2db 很好用的话。。。 要不楼主试着研究下 linq2db的自定义函数 然后 结合 freesql 尝试自己实现一下 弄个Demo 然后 提个 PR ?

MaceWindu commented 3 months ago

FYI, we at Linq To DB are moving away from mapping one member expression to another expression approach (Expression.Map* APIs) as being troublesome to approach with member builders which convert specific member call/property directly to SQL per-database