- 增加 SqlExt 常用开窗函数的自定义表达式解析;

This commit is contained in:
28810 2020-06-14 10:38:53 +08:00
parent 7a2000a29e
commit 72cccffc30
4 changed files with 117 additions and 4 deletions

View File

@ -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>

View File

@ -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();

View File

@ -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]
@ -39,4 +40,67 @@ public static class FreeSqlGlobalExpressionCallExtensions
expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} >= {expContext.Value.ParsedContent["start"]} and {expContext.Value.ParsedContent["that"]} < {expContext.Value.ParsedContent["end"]}"; expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} >= {expContext.Value.ParsedContent["start"]} and {expContext.Value.ParsedContent["that"]} < {expContext.Value.ParsedContent["end"]}";
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
}
} }

View File

@ -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;
ecc.RawExpression.Add(exp3MethodParams[0].Name, exp3.Arguments[0]); if (exp3MethodParams.Any())
ecc.ParsedContent.Add(exp3MethodParams[0].Name, exp3MethodParams[0].GetCustomAttributes(typeof(RawValueAttribute), true).Any() ? null : ExpressionLambdaToSql(exp3.Arguments[0], tsc)); {
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));
}
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)
exp3InvokeParams[a] = Expression.Lambda(exp3.Arguments[a]).Compile().DynamicInvoke(); {
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();
}
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;
} }