mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	- 增加 SqlExt 常用开窗函数的自定义表达式解析;
This commit is contained in:
		@@ -125,6 +125,13 @@
 | 
				
			|||||||
            清空状态数据
 | 
					            清空状态数据
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.DbSet`1.RemoveAsync(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            根据 lambda 条件删除数据
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="predicate"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.DbSet`1.Add(`0)">
 | 
					        <member name="M:FreeSql.DbSet`1.Add(`0)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            添加
 | 
					            添加
 | 
				
			||||||
@@ -479,5 +486,14 @@
 | 
				
			|||||||
            <param name="that"></param>
 | 
					            <param name="that"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:Microsoft.Extensions.DependencyInjection.FreeSqlRepositoryDependencyInjection.AddFreeRepository(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{FreeSql.FluentDataFilter},System.Reflection.Assembly[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            批量注入 Repository,可以参考代码自行调整
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="services"></param>
 | 
				
			||||||
 | 
					            <param name="globalDataFilter"></param>
 | 
				
			||||||
 | 
					            <param name="assemblies"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
    </members>
 | 
					    </members>
 | 
				
			||||||
</doc>
 | 
					</doc>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -155,6 +155,23 @@ namespace FreeSql.Tests
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void Test03()
 | 
					        public void Test03()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var sqlextOver = g.sqlserver.Select<Edi, EdiItem>()
 | 
				
			||||||
 | 
					                .InnerJoin((a, b) => b.Id == a.Id)
 | 
				
			||||||
 | 
					                .ToSql((a, b) => new
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Id = a.Id,
 | 
				
			||||||
 | 
					                    EdiId = b.Id,
 | 
				
			||||||
 | 
					                    over1 = SqlExt.Rank().Over().OrderBy(a.Id).OrderByDescending(b.EdiId).ToValue()
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            var sqlextOverToList = g.sqlserver.Select<Edi, EdiItem>()
 | 
				
			||||||
 | 
					                .InnerJoin((a, b) => b.Id == a.Id)
 | 
				
			||||||
 | 
					                .ToList((a, b) => new
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Id = a.Id,
 | 
				
			||||||
 | 
					                    EdiId = b.Id,
 | 
				
			||||||
 | 
					                    over1 = SqlExt.Rank().Over().OrderBy(a.Id).OrderByDescending(b.EdiId).ToValue()
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var tttrule = 8;
 | 
					            var tttrule = 8;
 | 
				
			||||||
            var tttid = new long[] { 18, 19, 4017 };
 | 
					            var tttid = new long[] { 18, 19, 4017 };
 | 
				
			||||||
            g.sqlserver.Update<Author123>().Set(it => it.SongId == (short)(it.SongId & ~tttrule)).Where(it => (it.SongId & tttrule) == tttrule && !tttid.Contains(it.Id)).ExecuteAffrows();
 | 
					            g.sqlserver.Update<Author123>().Set(it => it.SongId == (short)(it.SongId & ~tttrule)).Where(it => (it.SongId & tttrule) == tttrule && !tttid.Contains(it.Id)).ExecuteAffrows();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DataAnnotations;
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[ExpressionCall]
 | 
					[ExpressionCall]
 | 
				
			||||||
@@ -40,3 +41,66 @@ public static class FreeSqlGlobalExpressionCallExtensions
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [ExpressionCall]
 | 
				
			||||||
 | 
					    public static class SqlExt
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static ThreadLocal<ExpressionCallContext> expContext = new ThreadLocal<ExpressionCallContext>();
 | 
				
			||||||
 | 
					        static ThreadLocal<StringBuilder> expSb = new ThreadLocal<StringBuilder>();
 | 
				
			||||||
 | 
					        static ThreadLocal<bool> expSbIsOrderBy = new ThreadLocal<bool>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static ISqlOver<long> Rank() => Over<long>("RANK()");
 | 
				
			||||||
 | 
					        public static ISqlOver<long> DenseRank() => Over<long>("DENSE_RANK()");
 | 
				
			||||||
 | 
					        public static ISqlOver<long> Count() => Over<long>("COUNT()");
 | 
				
			||||||
 | 
					        public static ISqlOver<decimal> Sum(object column) => Over<decimal>($"Sum({expContext.Value.ParsedContent["column"]})");
 | 
				
			||||||
 | 
					        public static ISqlOver<decimal> Avg() => Over<decimal>($"AVG({expContext.Value.ParsedContent["column"]})");
 | 
				
			||||||
 | 
					        public static ISqlOver<T> Max<T>(T column) => Over<T>($"MAX({expContext.Value.ParsedContent["column"]})");
 | 
				
			||||||
 | 
					        public static ISqlOver<T> Min<T>(T column) => Over<T>($"MIN({expContext.Value.ParsedContent["column"]})");
 | 
				
			||||||
 | 
					        public static ISqlOver<long> RowNumber() => Over<long>("ROW_NUMBER()");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #region .. over([partition by ..] order by ...)
 | 
				
			||||||
 | 
					        static ISqlOver<TValue> Over<TValue>(string sqlFunc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            expSb.Value = new StringBuilder();
 | 
				
			||||||
 | 
					            expSbIsOrderBy.Value = false;
 | 
				
			||||||
 | 
					            expSb.Value.Append($"{sqlFunc} ");
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static ISqlOver<TValue> Over<TValue>(this ISqlOver<TValue> that)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            expSb.Value.Append("OVER(");
 | 
				
			||||||
 | 
					            return that;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static ISqlOver<TValue> PartitionBy<TValue>(this ISqlOver<TValue> that, object column)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            expSb.Value.Append("PARTITION BY ").Append(expContext.Value.ParsedContent["column"]).Append(",");
 | 
				
			||||||
 | 
					            return that;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static ISqlOver<TValue> OrderBy<TValue>(this ISqlOver<TValue> that, object column) => OrderBy(that, false);
 | 
				
			||||||
 | 
					        public static ISqlOver<TValue> OrderByDescending<TValue>(this ISqlOver<TValue> that, object column) => OrderBy(that, true);
 | 
				
			||||||
 | 
					        static ISqlOver<TValue> OrderBy<TValue>(this ISqlOver<TValue> that, bool isDesc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sb = expSb.Value;
 | 
				
			||||||
 | 
					            if (expSbIsOrderBy.Value == false)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                sb.Append("ORDER BY ");
 | 
				
			||||||
 | 
					                expSbIsOrderBy.Value = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sb.Append(expContext.Value.ParsedContent["column"]);
 | 
				
			||||||
 | 
					            if (isDesc) sb.Append(" desc");
 | 
				
			||||||
 | 
					            sb.Append(",");
 | 
				
			||||||
 | 
					            return that;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static TValue ToValue<TValue>(this ISqlOver<TValue> that)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sb = expSb.Value.ToString().TrimEnd(',');
 | 
				
			||||||
 | 
					            expSb.Value.Clear();
 | 
				
			||||||
 | 
					            expContext.Value.Result = $"{sb})";
 | 
				
			||||||
 | 
					            return default;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public interface ISqlOver<TValue> { }
 | 
				
			||||||
 | 
					        #endregion
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -627,8 +627,11 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                        };
 | 
					                        };
 | 
				
			||||||
                        var exp3MethodParams = exp3.Method.GetParameters();
 | 
					                        var exp3MethodParams = exp3.Method.GetParameters();
 | 
				
			||||||
                        var dbParamsIndex = tsc.dbParams?.Count;
 | 
					                        var dbParamsIndex = tsc.dbParams?.Count;
 | 
				
			||||||
 | 
					                        if (exp3MethodParams.Any())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
                            ecc.RawExpression.Add(exp3MethodParams[0].Name, exp3.Arguments[0]);
 | 
					                            ecc.RawExpression.Add(exp3MethodParams[0].Name, exp3.Arguments[0]);
 | 
				
			||||||
                            ecc.ParsedContent.Add(exp3MethodParams[0].Name, exp3MethodParams[0].GetCustomAttributes(typeof(RawValueAttribute), true).Any() ? null : ExpressionLambdaToSql(exp3.Arguments[0], tsc));
 | 
					                            ecc.ParsedContent.Add(exp3MethodParams[0].Name, exp3MethodParams[0].GetCustomAttributes(typeof(RawValueAttribute), true).Any() ? null : ExpressionLambdaToSql(exp3.Arguments[0], tsc));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                        if (tsc.dbParams?.Count > dbParamsIndex) ecc.DbParameter = tsc.dbParams.Last();
 | 
					                        if (tsc.dbParams?.Count > dbParamsIndex) ecc.DbParameter = tsc.dbParams.Last();
 | 
				
			||||||
                        List<DbParameter> oldDbParams = tsc.SetDbParamsReturnOld(null);
 | 
					                        List<DbParameter> oldDbParams = tsc.SetDbParamsReturnOld(null);
 | 
				
			||||||
                        for (var a = 1; a < exp3.Arguments.Count; a++)
 | 
					                        for (var a = 1; a < exp3.Arguments.Count; a++)
 | 
				
			||||||
@@ -646,7 +649,20 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                var eccContent = ecc.ParsedContent[exp3MethodParams[a].Name];
 | 
					                                var eccContent = ecc.ParsedContent[exp3MethodParams[a].Name];
 | 
				
			||||||
                                if (eccContent == null)
 | 
					                                if (eccContent == null)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    var isdyInvoke = true;
 | 
				
			||||||
 | 
					                                    if (exp3.Arguments[a].NodeType == ExpressionType.Call) //判断如果参数也是标记 ExpressionCall
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        var exp3ArgsACallExp = exp3.Arguments[a] as MethodCallExpression;
 | 
				
			||||||
 | 
					                                        if (exp3ArgsACallExp.Object == null && (
 | 
				
			||||||
 | 
					                                            _dicTypeExistsExpressionCallAttribute.GetOrAdd(exp3ArgsACallExp.Method.DeclaringType, dttp => dttp.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any()) ||
 | 
				
			||||||
 | 
					                                            exp3ArgsACallExp.Method.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any()
 | 
				
			||||||
 | 
					                                            ))
 | 
				
			||||||
 | 
					                                            isdyInvoke = false;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if (isdyInvoke)
 | 
				
			||||||
                                        exp3InvokeParams[a] = Expression.Lambda(exp3.Arguments[a]).Compile().DynamicInvoke();
 | 
					                                        exp3InvokeParams[a] = Expression.Lambda(exp3.Arguments[a]).Compile().DynamicInvoke();
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
                                else if (exp3.Arguments[a].IsParameter())
 | 
					                                else if (exp3.Arguments[a].IsParameter())
 | 
				
			||||||
                                    exp3InvokeParams[a] = exp3.Arguments[a].Type.CreateInstanceGetDefaultValue();
 | 
					                                    exp3InvokeParams[a] = exp3.Arguments[a].Type.CreateInstanceGetDefaultValue();
 | 
				
			||||||
                                else
 | 
					                                else
 | 
				
			||||||
@@ -668,7 +684,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            var sqlRet = exp3.Method.Invoke(null, exp3InvokeParams);
 | 
					                            var sqlRet = exp3.Method.Invoke(null, exp3InvokeParams);
 | 
				
			||||||
                            if (string.IsNullOrEmpty(ecc.Result) && sqlRet is string) ecc.Result = string.Concat(sqlRet);
 | 
					                            if (string.IsNullOrEmpty(ecc.Result) && sqlRet is string) ecc.Result = string.Concat(sqlRet);
 | 
				
			||||||
                            if (string.IsNullOrEmpty(ecc.Result)) ecc.Result = ecc.ParsedContent[exp3MethodParams[0].Name];
 | 
					                            if (string.IsNullOrEmpty(ecc.Result) && exp3MethodParams.Any()) ecc.Result = ecc.ParsedContent[exp3MethodParams[0].Name];
 | 
				
			||||||
                            if (ecc.UserParameters?.Any() == true) tsc.dbParams?.AddRange(ecc.UserParameters);
 | 
					                            if (ecc.UserParameters?.Any() == true) tsc.dbParams?.AddRange(ecc.UserParameters);
 | 
				
			||||||
                            return ecc.Result;
 | 
					                            return ecc.Result;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user