diff --git a/LightORM.slnx b/LightORM.slnx
index 0b2286f..a51efaf 100644
--- a/LightORM.slnx
+++ b/LightORM.slnx
@@ -24,6 +24,7 @@
+
diff --git "a/doc/\347\211\210\346\234\254\346\227\245\345\277\227.md" "b/doc/\347\211\210\346\234\254\346\227\245\345\277\227.md"
index b78fa0e..11e8b45 100644
--- "a/doc/\347\211\210\346\234\254\346\227\245\345\277\227.md"
+++ "b/doc/\347\211\210\346\234\254\346\227\245\345\277\227.md"
@@ -1,5 +1,32 @@
# 版本功能更新记录
+## v2026.02.11.1
+- ⚡️新增表达式解析缓存功能,默认启用,可以通过`IExpressionContextSetup.SetEnableExpressionCache`进行全局配置
+- ⚡️内部高频使用的对象新增对象池
+- ⚡️使用日期作为版本号
+
+
+#### 新版本(开启表达式解析缓存)
+| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
+|----------------------- |----------:|----------:|----------:|--------:|-------:|----------:|
+| SelectCTE | 89.498 us | 1.7850 us | 1.6697 us | 10.7422 | 0.4883 | 89.2 KB |
+| SelectCTEOptimized | 84.509 us | 1.4743 us | 1.3791 us | 10.2539 | 0.7324 | 85.68 KB |
+| SelectWithArrayAccess | 7.799 us | 0.1476 us | 0.1812 us | 0.9460 | 0.1831 | 7.75 KB |
+| SelectWithContainArray | 8.465 us | 0.1680 us | 0.2665 us | 0.9155 | 0.1831 | 7.65 KB |
+#### 新版本(关闭表达式解析缓存)
+| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
+|----------------------- |-----------:|----------:|----------:|--------:|-------:|----------:|
+| SelectCTE | 135.588 us | 2.6832 us | 4.2558 us | 12.2070 | 0.9766 | 103.57 KB |
+| SelectCTEOptimized | 129.420 us | 2.5883 us | 3.8741 us | 12.2070 | 0.9766 | 100.88 KB |
+| SelectWithArrayAccess | 5.580 us | 0.1010 us | 0.1081 us | 0.9155 | 0.0153 | 7.55 KB |
+| SelectWithContainArray | 6.253 us | 0.1131 us | 0.1003 us | 0.8850 | - | 7.27 KB |
+#### v3.2.1
+| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
+|----------------------- |-----------:|----------:|----------:|--------:|-------:|----------:|
+| SelectCTE | 134.840 us | 2.6678 us | 3.2762 us | 13.6719 | 0.9766 | 115.39 KB |
+| SelectCTEOptimized | 126.395 us | 2.4247 us | 2.4900 us | 13.1836 | 0.9766 | 111.5 KB |
+| SelectWithArrayAccess | 5.606 us | 0.1063 us | 0.1181 us | 1.0071 | - | 8.3 KB |
+| SelectWithContainArray | 6.316 us | 0.1251 us | 0.1489 us | 0.9766 | - | 8.1 KB |
## v3.2.1
- 🛠`DbParameterReader`优化
- 🛠解析表达式时,读取参数值的方式优化,表达式树编译缓存委托后直接调用
diff --git a/src/LightORM/AssemblyInfo.cs b/src/LightORM/AssemblyInfo.cs
index 17ec518..2bee556 100644
--- a/src/LightORM/AssemblyInfo.cs
+++ b/src/LightORM/AssemblyInfo.cs
@@ -26,5 +26,6 @@ internal static class DebugControl
{
public static readonly bool ShowExpressionResolveDebugInfo = false;
public static readonly bool ShowSqlExecutorDebugInfo = true;
+ public static readonly bool ShowExpressionHashCodeDebugInfo = true;
}
}
\ No newline at end of file
diff --git a/src/LightORM/Builder/DeleteBuilder.cs b/src/LightORM/Builder/DeleteBuilder.cs
index 2bd4a2d..76530e4 100644
--- a/src/LightORM/Builder/DeleteBuilder.cs
+++ b/src/LightORM/Builder/DeleteBuilder.cs
@@ -15,7 +15,7 @@ internal record DeleteBuilder : SqlBuilder
public List? BatchInfos { get; set; }
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
- if (expInfo.ResolveOptions?.SqlType == SqlPartial.Where)
+ if (expInfo.ResolveOptions.SqlType == SqlPartial.Where)
{
if (result.UseNavigate)
{
@@ -26,11 +26,9 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
{
continue;
}
- var navSqlBuilder = new SelectBuilder
- {
- IsSubQuery = true,
- Level = 1
- };
+ var navSqlBuilder = SelectBuilder.GetSelectBuilder();
+ navSqlBuilder.IsSubQuery = true;
+ navSqlBuilder.Level = 1;
navSqlBuilder.SelectedTables.Add(MainTable);
var navInfo = navColumn.NavigateInfo!;
var mainCol = MainTable.GetColumnInfo(navInfo.MainName!);
diff --git a/src/LightORM/Builder/InsertBuilder.cs b/src/LightORM/Builder/InsertBuilder.cs
index c28b48d..18594bf 100644
--- a/src/LightORM/Builder/InsertBuilder.cs
+++ b/src/LightORM/Builder/InsertBuilder.cs
@@ -14,11 +14,11 @@ internal record InsertBuilder : SqlBuilder
public bool IsReturnIdentity { get; set; }
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
- if (expInfo.ResolveOptions?.SqlType == SqlPartial.Insert)
+ if (expInfo.ResolveOptions.SqlType == SqlPartial.Insert)
{
Members.AddRange(result.Members!);
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Ignore)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.Ignore)
{
IgnoreMembers.AddRange(result.Members!);
}
diff --git a/src/LightORM/Builder/SelectBuilder.cs b/src/LightORM/Builder/SelectBuilder.cs
index 1ea3a4d..3f01177 100644
--- a/src/LightORM/Builder/SelectBuilder.cs
+++ b/src/LightORM/Builder/SelectBuilder.cs
@@ -1,4 +1,5 @@
using LightORM.Extension;
+using LightORM.Performances;
using System.Text;
namespace LightORM.Builder;
@@ -19,10 +20,9 @@ internal record SelectBuilder : SqlBuilder, ISelectSqlBuilder
{
public SelectBuilder()
{
- //DbType = dbType;
IncludeContext = new IncludeContext();
- //Indent = new Lazy(() => new string(' ', 4 * Level));
}
+ public static SelectBuilder GetSelectBuilder() => new();//SelectBuilderPool.Rent();
public string Id { get; } = $"{Guid.NewGuid():N}";
public int PageIndex { get; set; }
public int PageSize { get; set; }
@@ -46,7 +46,7 @@ public SelectBuilder()
public List Joins { get; set; } = [];
public List Having { get; set; } = [];
public List Includes { get; set; } = [];
- public IncludeContext IncludeContext { get; set; } = default!;
+ public IncludeContext IncludeContext { get; set; }
public List GroupBy { get; set; } = [];
public List OrderBy { get; set; } = [];
@@ -87,7 +87,7 @@ protected override void BeforeResolveExpressions(ResolveContext context)
}
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
- if (expInfo.ResolveOptions?.SqlType == SqlPartial.Where)
+ if (expInfo.ResolveOptions.SqlType == SqlPartial.Where)
{
if (result.UseNavigate)
{
@@ -116,7 +116,7 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
Where.Add(result.SqlString!);
}
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Join)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.Join)
{
var joinInfo = Joins.FirstOrDefault(j => j.ExpressionId == expInfo.Id);
if (joinInfo != null)
@@ -124,7 +124,7 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
joinInfo.Where = result.SqlString!;
}
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Select)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.Select)
{
if (result.UseNavigate)
{
@@ -146,16 +146,16 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
SelectValue = result.SqlString!;
}
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.GroupBy)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.GroupBy)
{
GroupBy.Add(result.SqlString!);
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.OrderBy)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.OrderBy)
{
OrderBy.Add(result.SqlString!);
AdditionalValue = expInfo.AdditionalParameter;
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Having)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.Having)
{
Having.Add(result.SqlString!);
}
@@ -251,17 +251,21 @@ private void BuildFromString(StringBuilder sql, ICustomDatabase database)
public override string ToSqlString(ICustomDatabase database)
{
//SubQuery?.ResolveExpressions();
- StringBuilder sql = new();
+ var estimatedSize = EstimateSqlLength();
+ StringBuilder sql = new(estimatedSize);
Build(sql, database, Level);
HandleSqlParameters(sql, database);
sql.Trim();
- return sql.ToString();
+ var sqlString = sql.ToString();
+ //SelectBuilderPool.Return(this);
+ return sqlString;
}
public void Build(StringBuilder sql, ICustomDatabase database, int currentLevel)
{
ResolveExpressions(database);
+
var ident = new string(' ', 4 * currentLevel);
if (InsertInfo.HasValue)
{
@@ -417,4 +421,140 @@ public void Build(StringBuilder sql, ICustomDatabase database, int currentLevel)
}
}
}
+
+ int EstimateSqlLength(int currentLevel = 0)
+ {
+ int total = 0;
+ const int indentPerLevel = 4;
+ var indent = indentPerLevel * currentLevel;
+
+ // SELECT
+ total += indent + 10 + (IsDistinct ? 9 : 0);
+ if (SelectValue != null) total += SelectValue.Length;
+ total += 2; // \n
+
+ // FROM / SubQuery
+ if (SubQuery != null)
+ {
+ total += indent + 7;
+ total += SubQuery.EstimateSqlLength(currentLevel + 1);
+ total += indent + 3;
+ if (MainTable.Alias != null) total += MainTable.Alias.Length;
+ total += 2;
+ }
+ else
+ {
+ total += indent + 5;
+ for (int i = 0; i < SelectedTables.Count; i++)
+ {
+ if (i > 0) total += 2; // ", "
+ var t = SelectedTables[i];
+ total += t.TableName.Length + 2;
+ if (t.Alias != null) total += 1 + t.Alias.Length;
+ }
+ total += 1; // \n
+ }
+
+ // JOINs
+ for (int i = 0; i < Joins.Count; i++)
+ {
+ var join = Joins[i];
+ total += indent + 10; // "INNER JOIN "
+ if (join.IsSubQuery && join.SubQuery != null)
+ {
+ total += join.SubQuery.EstimateSqlLength(currentLevel + 1);
+ }
+ else if (join.EntityInfo != null)
+ {
+ total += join.EntityInfo.TableName.Length + 2;
+ if (join.EntityInfo.Alias != null)
+ total += 1 + join.EntityInfo.Alias.Length;
+ }
+ total += 4; // " ON "
+ if (join.Where != null) total += join.Where.Length;
+ else total += 10;
+ total += 2; // \n
+ }
+
+ // WHERE
+ if (Where.Count > 0)
+ {
+ total += indent + 7;
+ for (int i = 0; i < Where.Count; i++)
+ {
+ if (i > 0) total += 5; // " AND "
+ total += Where[i].Length;
+ }
+ total += 1; // \n
+ }
+
+ // GROUP BY
+ if (GroupBy.Count > 0)
+ {
+ total += indent + 12;
+ if (IsRollup) total += 9;
+ for (int i = 0; i < GroupBy.Count; i++)
+ {
+ if (i > 0) total += 2; // ", "
+ total += GroupBy[i].Length;
+ }
+ if (IsRollup) total += 1;
+ total += 1; // \n
+ }
+
+ // ORDER BY
+ if (OrderBy.Count > 0)
+ {
+ total += indent + 10;
+ for (int i = 0; i < OrderBy.Count; i++)
+ {
+ if (i > 0) total += 2;
+ total += OrderBy[i].Length;
+ }
+ // ⚠️ AdditionalValue: 避免 ToString()
+ // 如果你知道它通常是 string/int,可特殊处理:
+ if (AdditionalValue is string s) total += s.Length;
+ else if (AdditionalValue is not null)
+ {
+ // 保守估计:最多 10 个字符(如 "DESC")
+ total += 10;
+ }
+ total += 1; // \n
+ }
+
+ // Paging (Take/Skip)
+ if (Take > 0)
+ {
+ total += 50; // 保守估计 LIMIT/OFFSET/FETCH
+ }
+
+ // CTE (WITH ...)
+ if (TempViews.Count > 0)
+ {
+ total += 5; // "WITH "
+ foreach (var view in TempViews)
+ {
+ total += view.EstimateSqlLength(currentLevel + 1);
+ total += 2; // "),"
+ }
+ }
+
+ // UNION
+ foreach (var union in Unions)
+ {
+ total += indent + 12; // "UNION ALL\n"
+ total += union.SqlBuilder.EstimateSqlLength(currentLevel);
+ }
+
+ // Temp wrapper: " name AS (\n ... \n)"
+ if (IsTemp)
+ {
+ total += (TempName?.Length ?? 10) + 6; // " name AS ("
+ total += 2; // "\n...\n)"
+ }
+
+ // 安全边际
+ return Math.Max(64, (int)(total * 1.2) + 50);
+ }
}
+
diff --git a/src/LightORM/Builder/SqlBuilder.cs b/src/LightORM/Builder/SqlBuilder.cs
index f6f525d..3461bc9 100644
--- a/src/LightORM/Builder/SqlBuilder.cs
+++ b/src/LightORM/Builder/SqlBuilder.cs
@@ -8,7 +8,6 @@ namespace LightORM.Builder;
internal abstract record SqlBuilder : ISqlBuilder
{
public static string N { get; } = Environment.NewLine;
-
public ExpressionInfoProvider Expressions { get; } = new ExpressionInfoProvider();
public TableInfo MainTable => SelectedTables[0];
public List SelectedTables { get; set; } = [];
@@ -97,15 +96,17 @@ protected void ResolveExpressions(ICustomDatabase database)
foreach (var item in Expressions.ExpressionInfos.Values.Where(item => !item.Completed))
{
//item.ResolveOptions!.DbType = DbType;
- item.ResolveOptions!.ParameterPartialIndex = index;
- var result = item.Expression.Resolve(item.ResolveOptions!, ResolveCtx);
+ //item.ResolveOptions = item.ResolveOptions with { ParameterPartialIndex = index };
+ item.ResolveOptions.ParameterPartialIndex = index;
+ var result = item.Expression.Resolve(item.ResolveOptions, ResolveCtx);
item.Completed = true;
if (!string.IsNullOrEmpty(item.Template))
{
result.SqlString = string.Format(item.Template, result.SqlString);
}
HandleResult(database, item, result);
- DbParameterInfos.AddRange(result.DbParameters ?? []);
+ if (result.DbParameters != null)
+ DbParameterInfos.AddRange(result.DbParameters);
index++;
}
}
diff --git a/src/LightORM/Builder/UpdateBuilder.cs b/src/LightORM/Builder/UpdateBuilder.cs
index 70fd910..fb1ca0e 100644
--- a/src/LightORM/Builder/UpdateBuilder.cs
+++ b/src/LightORM/Builder/UpdateBuilder.cs
@@ -21,12 +21,12 @@ internal record UpdateBuilder : SqlBuilder
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
- if (expInfo.ResolveOptions?.SqlType == SqlPartial.Where)
+ if (expInfo.ResolveOptions.SqlType == SqlPartial.Where)
{
Where.Add(result.SqlString!);
- WhereMembers.AddRange(result?.Members?.Distinct() ?? []);
+ WhereMembers.AddRange(result.Members?.Distinct() ?? []);
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Update)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.Update)
{
if (expInfo.AdditionalParameter is null)
{
@@ -46,7 +46,7 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
}
}
}
- else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Ignore)
+ else if (expInfo.ResolveOptions.SqlType == SqlPartial.Ignore)
{
IgnoreMembers.AddRange(result.Members!);
//IgnoreMembers = new(result.Members!)
diff --git a/src/LightORM/ExpressionSql/ExpressionCoreSql.Union.cs b/src/LightORM/ExpressionSql/ExpressionCoreSql.Union.cs
index e5251e4..ab42436 100644
--- a/src/LightORM/ExpressionSql/ExpressionCoreSql.Union.cs
+++ b/src/LightORM/ExpressionSql/ExpressionCoreSql.Union.cs
@@ -11,7 +11,7 @@ public IExpSelect FromQuery(IExpSelect select)
public IExpSelect FromTemp(IExpTemp temp)
{
- var builder = new SelectBuilder();
+ var builder = SelectBuilder.GetSelectBuilder();
builder.HandleTempsRecursion(temp.SqlBuilder);
builder.SelectedTables.Add(temp.ResultTable);
return new SelectProvider1(Ado, builder);
diff --git a/src/LightORM/ExpressionSql/ExpressionSqlBuilder.cs b/src/LightORM/ExpressionSql/ExpressionSqlBuilder.cs
index f4ac2b4..0c4c186 100644
--- a/src/LightORM/ExpressionSql/ExpressionSqlBuilder.cs
+++ b/src/LightORM/ExpressionSql/ExpressionSqlBuilder.cs
@@ -32,10 +32,12 @@ internal partial class ExpressionSqlOptions
private readonly static ConcurrentDictionary databaseHandlers = [];
private readonly static ConcurrentDictionary stateLessInterceptors = [];
private static int poolSize = Environment.ProcessorCount * 4;
+ private static int objectPoolSize = Environment.ProcessorCount * 8;
internal static TableGenerateOption StaticTableGenOption { get; set; } = new();
private static string? defaultDbKey;
private static bool useParameterized = true;
+ private static bool enableExpressionCache = true;
static ExpressionSqlOptions()
{
Instance = new(() => new ExpressionSqlOptions());
@@ -85,12 +87,18 @@ public static void SetUseParameterized(bool use)
{
useParameterized = use;
}
+ public static void SetEnableExpressionCache(bool enable)
+ {
+ enableExpressionCache = enable;
+ }
}
internal partial class ExpressionSqlOptions
{
public static Lazy Instance { get; }
public int PoolSize => poolSize;
+ public int InternalObjectPoolSize => objectPoolSize;
+ public bool EnableExpressionCache => enableExpressionCache;
public string DefaultDbKey
{
get
@@ -105,7 +113,7 @@ public string DefaultDbKey
}
public bool UseParameterized => useParameterized;
public IServiceProvider? Services { get; set; }
- private ICollection allInterceptors;
+ private readonly ICollection allInterceptors;
public ICollection Interceptors => allInterceptors;
public ConcurrentDictionary DatabaseProviders { get; }
public ConcurrentDictionary CustomDatabases { get; }
@@ -154,6 +162,12 @@ public IExpressionContextSetup SetConnectionPoolSize(int poolSize)
return this;
}
+ public IExpressionContextSetup SetEnableExpressionCache(bool enable)
+ {
+ ExpressionSqlOptions.SetEnableExpressionCache(enable);
+ return this;
+ }
+
public IExpressionContextSetup SetDatabase(string? key, DbBaseType dbBaseType, IDatabaseProvider provider)
{
ExpressionSqlOptions.SetDatabase(key, dbBaseType, provider);
diff --git a/src/LightORM/Extension/CustomDatabaseExtensions.cs b/src/LightORM/Extension/CustomDatabaseExtensions.cs
index 0642eb9..c08f1e0 100644
--- a/src/LightORM/Extension/CustomDatabaseExtensions.cs
+++ b/src/LightORM/Extension/CustomDatabaseExtensions.cs
@@ -1,4 +1,5 @@
-using System.Text;
+using LightORM.Performances;
+using System.Text;
namespace LightORM.Extension;
@@ -44,15 +45,25 @@ public static StringBuilder AppendEmphasis(this StringBuilder sql, string name,
public static StringBuilder AppendJoined(this StringBuilder sql, List values, string separator)
{
- bool first = true;
- foreach (var item in values)
+ if (values.Count == 0) return sql;
+ sql.Append(values[0]);
+ for (int i = 1; i < values.Count; i++)
{
- if (!first)
+ sql.Append(separator);
+ sql.Append(values[i]);
+ }
+ return sql;
+ }
+
+ public static StringBuilder AppendJoined(this StringBuilder sql, ref SlimList values, string separator)
+ {
+ for (int i = 0; i < values.Count; i++)
+ {
+ if (i > 0)
{
sql.Append(separator);
}
- first = false;
- sql.Append(item);
+ sql.Append(values[i]);
}
return sql;
}
diff --git a/src/LightORM/Extension/ExpressionContextExtension.cs b/src/LightORM/Extension/ExpressionContextExtension.cs
index 9b45927..a2b0cab 100644
--- a/src/LightORM/Extension/ExpressionContextExtension.cs
+++ b/src/LightORM/Extension/ExpressionContextExtension.cs
@@ -141,7 +141,7 @@ private static void HandleFromTemp(SelectBuilder sqlbuilder, params IExpTemp[] t
public static IExpSelect FromTemp(this IExpressionContext context
, IExpTemp temp1, IExpTemp temp2)
{
- var builder = new SelectBuilder();
+ var builder = SelectBuilder.GetSelectBuilder();
HandleFromTemp(builder, temp1, temp2);
return new SelectProvider2(context.Ado, builder);
}
@@ -149,7 +149,7 @@ public static IExpSelect FromTemp(this IExpressi
public static IExpSelect FromTemp(this IExpressionContext context
, IExpTemp temp1, IExpTemp temp2, IExpTemp temp3)
{
- var builder = new SelectBuilder();
+ var builder = SelectBuilder.GetSelectBuilder();
HandleFromTemp(builder, temp1, temp2, temp3);
return new SelectProvider3(context.Ado, builder);
}
@@ -157,7 +157,7 @@ public static IExpSelect FromTemp FromTemp(this IExpressionContext context
, IExpTemp temp1, IExpTemp temp2, IExpTemp temp3, IExpTemp temp4)
{
- var builder = new SelectBuilder();
+ var builder = SelectBuilder.GetSelectBuilder();
HandleFromTemp(builder, temp1, temp2, temp3, temp4);
return new SelectProvider4(context.Ado, builder);
}
@@ -165,7 +165,7 @@ public static IExpSelect FromTemp FromTemp(this IExpressionContext context
, IExpTemp temp1, IExpTemp temp2, IExpTemp temp3, IExpTemp temp4, IExpTemp temp5)
{
- var builder = new SelectBuilder();
+ var builder = SelectBuilder.GetSelectBuilder();
HandleFromTemp(builder, temp1, temp2, temp3, temp4, temp5);
return new SelectProvider5(context.Ado, builder);
}
diff --git a/src/LightORM/Extension/GroupSelectExtensions.cs b/src/LightORM/Extension/GroupSelectExtensions.cs
index 6589e5c..a80d02d 100644
--- a/src/LightORM/Extension/GroupSelectExtensions.cs
+++ b/src/LightORM/Extension/GroupSelectExtensions.cs
@@ -1,4 +1,6 @@
-namespace LightORM;
+using LightORM.Utils.Vistors;
+
+namespace LightORM;
public static class GroupSelectExtensions
{
diff --git a/src/LightORM/Extension/IncludeContextExtensions.cs b/src/LightORM/Extension/IncludeContextExtensions.cs
index c4cd522..fd3f0b9 100644
--- a/src/LightORM/Extension/IncludeContextExtensions.cs
+++ b/src/LightORM/Extension/IncludeContextExtensions.cs
@@ -82,7 +82,7 @@ public static SelectBuilder BuildIncludeSqlBuilder(ICustomDatabase database, obj
private static SelectBuilder BuildSql(ICustomDatabase database, IncludeInfo include, object item)
{
- SelectBuilder selectSql = new();
+ SelectBuilder selectSql = SelectBuilder.GetSelectBuilder();
var selectedType = include.NavigateInfo!.NavigateType;
selectSql.SelectedTables.Add(TableInfo.Create(selectedType));
//selectSql.DbParameterStartIndex = include.ExpressionResolvedResult!.DbParameters?.Count ?? 0;
diff --git a/src/LightORM/Extension/SelectExtensions.cs b/src/LightORM/Extension/SelectExtensions.cs
index e15d7e0..498424b 100644
--- a/src/LightORM/Extension/SelectExtensions.cs
+++ b/src/LightORM/Extension/SelectExtensions.cs
@@ -1,4 +1,6 @@
-namespace LightORM;
+using LightORM.Utils.Vistors;
+
+namespace LightORM;
// public static partial class Select1Ex
// {
diff --git a/src/LightORM/Extension/SelectHandleExtensions.cs b/src/LightORM/Extension/SelectHandleExtensions.cs
index def4427..c85391a 100644
--- a/src/LightORM/Extension/SelectHandleExtensions.cs
+++ b/src/LightORM/Extension/SelectHandleExtensions.cs
@@ -149,7 +149,7 @@ internal static void HandleResult(this IExpSelect select, Expression? exp, strin
internal static SelectProvider1 HandleSubQuery(this IExpSelect select, string? alias = null)
{
select.SqlBuilder.IsSubQuery = true;
- var builder = new SelectBuilder();
+ var builder = SelectBuilder.GetSelectBuilder();
var table = TableInfo.Create();
if (alias != null)
{
diff --git a/src/LightORM/Interfaces/IExpressionContextSetup.cs b/src/LightORM/Interfaces/IExpressionContextSetup.cs
index fa52ac5..f4837cb 100644
--- a/src/LightORM/Interfaces/IExpressionContextSetup.cs
+++ b/src/LightORM/Interfaces/IExpressionContextSetup.cs
@@ -7,6 +7,7 @@ public interface IExpressionContextSetup
IExpressionContextSetup SetDefault(string key);
IExpressionContextSetup SetUseParameterized(bool use);
IExpressionContextSetup SetConnectionPoolSize(int poolSize);
+ IExpressionContextSetup SetEnableExpressionCache(bool enable);
IExpressionContextSetup SetDatabase(string? key, DbBaseType dbBaseType, IDatabaseProvider provider);
IExpressionContextSetup SetTableContext(ITableContext context);
IExpressionContextSetup UseInterceptor() where T : AdoInterceptorBase;
diff --git a/src/LightORM/Interfaces/IResetable.cs b/src/LightORM/Interfaces/IResetable.cs
new file mode 100644
index 0000000..07916ef
--- /dev/null
+++ b/src/LightORM/Interfaces/IResetable.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LightORM.Interfaces;
+
+internal interface IResetable
+{
+ void Reset();
+}
diff --git a/src/LightORM/Models/ExpressionInfo.cs b/src/LightORM/Models/ExpressionInfo.cs
index 8dff517..6ab264f 100644
--- a/src/LightORM/Models/ExpressionInfo.cs
+++ b/src/LightORM/Models/ExpressionInfo.cs
@@ -11,7 +11,7 @@ public ExpressionInfo() { }
///
/// 解析Sql选项
///
- public SqlResolveOptions? ResolveOptions { get; set; }
+ public SqlResolveOptions ResolveOptions { get; set; }
///
/// 表达式
///
diff --git a/src/LightORM/Models/ExpressionResolvedResult.cs b/src/LightORM/Models/ExpressionResolvedResult.cs
index 0ab7291..23f4df8 100644
--- a/src/LightORM/Models/ExpressionResolvedResult.cs
+++ b/src/LightORM/Models/ExpressionResolvedResult.cs
@@ -1,7 +1,18 @@
namespace LightORM.Models;
-internal class ExpressionResolvedResult
+internal record ExpressionResolvedResult
{
+ public ExpressionResolvedResult(ExpressionResolver resolve)
+ {
+ SqlString = resolve.Sql.ToString();
+ Members = resolve.ResolvedMembers;
+ MemberOfNavigateMember = resolve.MemberOfNavigateMember;
+ UseNavigate = resolve.UseNavigate;
+ NavigateDeep = resolve.NavigateDeep;
+ NavigateMembers = resolve.NavigateMembers;
+ WindowFnPartials = resolve.WindowFnPartials;
+ NavigateWhereExpression = resolve.NavigateWhereExpression;
+ }
///
/// 解析生成的sql语句
///
@@ -13,17 +24,18 @@ internal class ExpressionResolvedResult
///
/// 解析到的成员
///
- public List? Members { get; set; }
+ public List? Members { get; }
///
/// 是否使用了导航属性
///
- public bool UseNavigate { get; set; }
- public int NavigateDeep { get; set; }
+ public bool UseNavigate { get; }
+ public int NavigateDeep { get; set; }
+ public bool NeedToExtractValues { get; set; }
///
/// 解析到的导航属性成员
///
- public List? NavigateMembers { get; set; }
- public string? MemberOfNavigateMember { get; set; }
- public Expression? NavigateWhereExpression { get; set; }
- public List? WindowFnPartials { get; set; }
+ public List? NavigateMembers { get; }
+ public string? MemberOfNavigateMember { get; }
+ public Expression? NavigateWhereExpression { get; }
+ public List? WindowFnPartials { get; }
}
diff --git a/src/LightORM/Performances/ExpressionResolverPool.cs b/src/LightORM/Performances/ExpressionResolverPool.cs
new file mode 100644
index 0000000..4247266
--- /dev/null
+++ b/src/LightORM/Performances/ExpressionResolverPool.cs
@@ -0,0 +1,67 @@
+using System.Collections.Concurrent;
+using System.Text;
+namespace LightORM.Performances;
+
+internal static class ExpressionResolverPool
+{
+ private static readonly ConcurrentStack pool = [];
+ public static ExpressionResolver Rent(SqlResolveOptions options, ResolveContext context)
+ {
+ if (pool.TryPop(out var resolver))
+ {
+ // 重置状态而不是创建新实例
+ ResetResolver(resolver, options, context);
+ return resolver;
+ }
+ return new ExpressionResolver(options, context);
+ }
+
+ public static void Return(ExpressionResolver resolver)
+ {
+ if (pool.Count < ExpressionSqlOptions.Instance.Value.InternalObjectPoolSize)
+ {
+ ClearResolver(resolver);
+ pool.Push(resolver);
+ }
+ }
+
+ private static void ResetResolver(ExpressionResolver resolver, SqlResolveOptions options, ResolveContext context)
+ {
+ // 重用StringBuilder,只需Clear
+ resolver.Sql.Clear();
+ resolver.Sql.EnsureCapacity(128); // 恢复初始容量
+
+ // 清空列表,重用底层数组
+ resolver.DbParameters.Clear();
+ resolver.Members.Clear();
+ resolver.ResolvedMembers.Clear();
+ resolver.NavigateMembers?.Clear();
+ resolver.WindowFnPartials?.Clear();
+
+ // 重置字段
+ resolver.Options = options;
+ resolver.Context = context;
+ resolver.IsNot = false;
+ resolver.UseNavigate = false;
+ resolver.NavigateDeep = 0;
+ resolver.Parameters = null;
+ resolver.ParameterPositionIndex = 0;
+ resolver.ResolveNullValue = false;
+ resolver.UseAs = true;
+ resolver.IsVisitConvert = false;
+ resolver.ContainVariable = false;
+ }
+
+ private static void ClearResolver(ExpressionResolver resolver)
+ {
+ // 清空但不释放大数组,如果太大,重建
+ if (resolver.Sql.Capacity > 4096)
+ resolver.Sql = new StringBuilder(128);
+
+ if (resolver.DbParameters.Capacity > 32)
+ resolver.DbParameters = new List(8);
+
+ if (resolver.ResolvedMembers.Capacity > 16)
+ resolver.ResolvedMembers = new List(4);
+ }
+}
\ No newline at end of file
diff --git a/src/LightORM/Performances/ExpressionVisitorPool.cs b/src/LightORM/Performances/ExpressionVisitorPool.cs
new file mode 100644
index 0000000..e7b2276
--- /dev/null
+++ b/src/LightORM/Performances/ExpressionVisitorPool.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LightORM.Performances;
+
+internal static class ExpressionVisitorPool
+ where T : ExpressionVisitor, IResetable, new()
+{
+ private static readonly ConcurrentStack pool = new();
+ public static T Rent()
+ {
+ if (pool.TryPop(out var visitor))
+ {
+ return visitor;
+ }
+ return new T();
+ }
+
+ public static void Return(T visitor)
+ {
+ if (pool.Count < ExpressionSqlOptions.Instance.Value.InternalObjectPoolSize)
+ {
+ visitor.Reset();
+ pool.Push(visitor);
+ }
+ }
+
+}
diff --git a/src/LightORM/Performances/SelectBuilderPool.cs b/src/LightORM/Performances/SelectBuilderPool.cs
new file mode 100644
index 0000000..198b426
--- /dev/null
+++ b/src/LightORM/Performances/SelectBuilderPool.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace LightORM.Performances;
+
+internal class SelectBuilderPool
+{
+ private static readonly ConcurrentStack pool = new();
+ public static SelectBuilder Rent()
+ {
+ if (pool.TryPop(out var builder))
+ {
+ ResetBuilder(builder);
+ return builder;
+ }
+ return new SelectBuilder();
+ }
+
+ public static void Return(SelectBuilder builder)
+ {
+ if (builder == null) return;
+
+ // 清理资源但不释放对象
+ ClearBuilder(builder);
+
+ if (pool.Count < ExpressionSqlOptions.Instance.Value.InternalObjectPoolSize)
+ pool.Push(builder);
+ }
+
+ private static void ResetBuilder(SelectBuilder builder)
+ {
+ // 清空列表但保留容量
+ builder.SelectedTables.Clear();
+ builder.Where.Clear();
+ builder.Joins.Clear();
+ builder.GroupBy.Clear();
+ builder.OrderBy.Clear();
+ builder.Having.Clear();
+ builder.Includes?.Clear();
+ builder.TempViews.Clear();
+ builder.Unions.Clear();
+ builder.DbParameters.Clear();
+ builder.Where.Clear();
+ builder.DbParameterInfos.Clear();
+
+ // 重置其他字段
+ builder.PageIndex = 0;
+ builder.PageSize = 0;
+ builder.Skip = 0;
+ builder.Take = 0;
+ builder.IsDistinct = false;
+ builder.IsRollup = false;
+ builder.SelectValue = "*";
+ builder.Level = 0;
+ builder.TableIndexFix = 0;
+ builder.IsSubQuery = false;
+ builder.IsTemp = false;
+ builder.IsUnion = false;
+ builder.TempName = null;
+ builder.InsertInfo = null;
+ builder.SubQuery = null;
+ builder.AdditionalValue = null;
+ builder.TargetObject = null;
+ builder.IsParameterized = true;
+
+ // 清空Expressions
+ builder.Expressions.ExpressionInfos.Clear();
+ }
+
+ private static void ClearBuilder(SelectBuilder builder)
+ {
+ // 如果列表容量过大,重建以释放内存
+ ShrinkListIfLarge(builder.Where);
+ ShrinkListIfLarge(builder.GroupBy);
+ ShrinkListIfLarge(builder.OrderBy);
+ ShrinkListIfLarge(builder.Joins);
+ // ... 其他列表
+ }
+
+ private static void ShrinkListIfLarge(List list)
+ {
+ if (list.Capacity > 64) // 如果容量太大
+ list = new List(8); // 重建为小容量
+ }
+}
diff --git a/src/LightORM/Performances/SlimList.cs b/src/LightORM/Performances/SlimList.cs
new file mode 100644
index 0000000..74dcf42
--- /dev/null
+++ b/src/LightORM/Performances/SlimList.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LightORM.Performances;
+
+internal struct SlimList
+{
+ private T _item0, _item1, _item2, _item3;
+ private T[]? _overflow;
+ private int _count;
+
+
+ public void Add(T item)
+ {
+ if (_count < 4)
+ {
+ switch (_count)
+ {
+ case 0:
+ _item0 = item;
+ break;
+ case 1:
+ _item1 = item;
+ break;
+ case 2:
+ _item2 = item;
+ break;
+ case 3:
+ _item3 = item;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // 溢出到数组
+ _overflow ??= new T[8];
+ if (_count - 4 >= _overflow.Length)
+ Array.Resize(ref _overflow, _overflow.Length * 2);
+ _overflow[_count - 4] = item;
+ }
+ _count++;
+ }
+
+
+ public int Count => _count;
+
+ public T this[int index]
+ {
+ get
+ {
+ if (index < 0 || index >= _count)
+ throw new IndexOutOfRangeException();
+ return index switch
+ {
+ < 4 => index switch
+ {
+ 0 => _item0,
+ 1 => _item1,
+ 2 => _item2,
+ 3 => _item3,
+ _ => throw new InvalidOperationException()
+ },
+ _ => _overflow![index - 4]
+ };
+ }
+ }
+}
diff --git a/src/LightORM/Providers/GroupSelectProvider.cs b/src/LightORM/Providers/GroupSelectProvider.cs
index 609aad7..d401fe6 100644
--- a/src/LightORM/Providers/GroupSelectProvider.cs
+++ b/src/LightORM/Providers/GroupSelectProvider.cs
@@ -1,4 +1,5 @@
-using System.Text;
+using LightORM.Utils.Vistors;
+using System.Text;
namespace LightORM.Providers
{
diff --git a/src/LightORM/Providers/Select/SelectProvider1.cs b/src/LightORM/Providers/Select/SelectProvider1.cs
index edcfe16..b426a6a 100644
--- a/src/LightORM/Providers/Select/SelectProvider1.cs
+++ b/src/LightORM/Providers/Select/SelectProvider1.cs
@@ -1,5 +1,6 @@
using LightORM.Extension;
using LightORM.Implements;
+using LightORM.Utils.Vistors;
using System.Threading;
namespace LightORM.Providers.Select;
@@ -16,7 +17,7 @@ public SelectProvider1(ISqlExecutor executor, SelectBuilder? builder = null)
{
if (builder == null)
{
- SqlBuilder = new SelectBuilder();
+ SqlBuilder = SelectBuilder.GetSelectBuilder();
//SqlBuilder.SelectedTables.Add(TableContext.GetTableInfo());
SqlBuilder.SelectedTables.Add(TableInfo.Create());
}
@@ -25,7 +26,7 @@ public SelectProvider1(ISqlExecutor executor, SelectBuilder? builder = null)
public SelectProvider1(string overriddenTableName, ISqlExecutor executor)
: base(executor)
{
- SqlBuilder = new SelectBuilder();
+ SqlBuilder = SelectBuilder.GetSelectBuilder();
SqlBuilder.SelectedTables.Add(TableInfo.Create(overriddenTableName));
}
diff --git a/src/LightORM/Providers/Select/SelectProvider2.cs b/src/LightORM/Providers/Select/SelectProvider2.cs
index 040f473..853767b 100644
--- a/src/LightORM/Providers/Select/SelectProvider2.cs
+++ b/src/LightORM/Providers/Select/SelectProvider2.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using LightORM.Utils.Vistors;
+using System.Threading;
namespace LightORM.Providers.Select;
@@ -9,7 +10,7 @@ public SelectProvider2(ISqlExecutor executor, SelectBuilder? builder = null)
{
if (builder == null)
{
- SqlBuilder = new SelectBuilder();
+ SqlBuilder = SelectBuilder.GetSelectBuilder();
SqlBuilder.SelectedTables.Add(TableInfo.Create(0));
SqlBuilder.SelectedTables.Add(TableInfo.Create(1));
}
diff --git a/src/LightORM/Repository/LightOrmQueryProvider.cs b/src/LightORM/Repository/LightOrmQueryProvider.cs
index 11a8dae..115fa7c 100644
--- a/src/LightORM/Repository/LightOrmQueryProvider.cs
+++ b/src/LightORM/Repository/LightOrmQueryProvider.cs
@@ -1,9 +1,10 @@
using LightORM.Extension;
+using LightORM.Utils.Vistors;
namespace LightORM.Repository;
internal class LightOrmQueryProvider : IQueryProvider
{
- private readonly SelectBuilder select = new();
+ private readonly SelectBuilder select = SelectBuilder.GetSelectBuilder();
private readonly ISqlExecutor ado;
private LambdaExpression? keySelector;
public LightOrmQueryProvider(ISqlExecutor ado, Type type)
diff --git a/src/LightORM/Utils/ExpressionResolver.cs b/src/LightORM/Utils/ExpressionResolver.cs
index a6e2832..6481e26 100644
--- a/src/LightORM/Utils/ExpressionResolver.cs
+++ b/src/LightORM/Utils/ExpressionResolver.cs
@@ -1,4 +1,5 @@
using LightORM.Extension;
+using LightORM.Performances;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
@@ -14,22 +15,52 @@ namespace LightORM;
internal static class ExpressionExtensions
{
+ private static readonly ConcurrentDictionary expressionResolvedResultCache = new();
public static ExpressionResolvedResult Resolve(this Expression? expression, SqlResolveOptions options, ResolveContext context)
{
- var resolve = new ExpressionResolver(options, context);
- resolve.Visit(expression);
- return new ExpressionResolvedResult
+
+ //resolve.Visit(expression);
+ //return new ExpressionResolvedResult(resolve);
+ //var resolve = new ExpressionResolver(options, context);
+ bool enableCache = ExpressionSqlOptions.Instance.Value.EnableExpressionCache;
+ ulong key = 0;
+ if (enableCache)
{
- SqlString = resolve.Sql.ToString(),
- DbParameters = resolve.DbParameters,
- Members = resolve.ResolvedMembers,
- MemberOfNavigateMember = resolve.MemberOfNavigateMember,
- UseNavigate = resolve.UseNavigate,
- NavigateDeep = resolve.NavigateDeep,
- NavigateMembers = resolve.NavigateMembers,
- WindowFnPartials = resolve.WindowFnPartials,
- NavigateWhereExpression = resolve.NavigateWhereExpression
- };
+ key = ExpressionHasher.Default.ComputeHash64(expression);
+ Debug.WriteLineIf(ShowExpressionHashCodeDebugInfo, $"hashcocde: {key}");
+ }
+ if (enableCache && expressionResolvedResultCache.TryGetValue(key, out var result))
+ {
+ //result.DbParameters
+ if (result.NeedToExtractValues)
+ {
+ var parameters = ExpressionValueExtract.Default.Extract(expression, options, context);
+ return result with { DbParameters = parameters };
+ }
+ return result;
+ }
+ else
+ {
+ var resolver = ExpressionResolverPool.Rent(options, context);
+ try
+ {
+ resolver.Visit(expression);
+ result = new(resolver)
+ {
+ NeedToExtractValues = resolver.ContainVariable
+ };
+ expressionResolvedResultCache.TryAdd(key, result);
+ if (resolver.DbParameters.Count > 0)
+ {
+ return result with { DbParameters = [.. resolver.DbParameters] };
+ }
+ return result;
+ }
+ finally
+ {
+ ExpressionResolverPool.Return(resolver);
+ }
+ }
}
public static string OperatorParser(this ExpressionType expressionNodeType, bool isNull)
@@ -56,8 +87,8 @@ ExpressionType.Or or
}
internal class ExpressionResolver(SqlResolveOptions options, ResolveContext context) : IExpressionResolver
{
- public SqlResolveOptions Options { get; } = options;
- public ResolveContext Context { get; } = context;
+ public SqlResolveOptions Options { get; set; } = options;
+ public ResolveContext Context { get; set; } = context;
public List DbParameters { get; set; } = [];
public StringBuilder Sql { get; set; } = new StringBuilder(128);
public Stack Members { get; set; } = [];
@@ -74,7 +105,13 @@ internal class ExpressionResolver(SqlResolveOptions options, ResolveContext cont
private ISqlMethodResolver MethodResolver => Context.Database.MethodResolver;
private ICustomDatabase Database => Context.Database;
public Expression? Body => bodyExpression;
- public ReadOnlyCollection? Parameters => parametersExpression;
+ public bool ContainVariable { get; set; }
+ public ReadOnlyCollection? Parameters
+ {
+ get => parametersExpression;
+ set => parametersExpression = value;
+ }
+
public Expression? Visit(Expression? expression)
{
//Debug.Write($"");
@@ -98,11 +135,9 @@ internal class ExpressionResolver(SqlResolveOptions options, ResolveContext cont
private const string AS_LITERAL = " AS ";
Expression? bodyExpression;
ReadOnlyCollection? parametersExpression;
- int parameterPositionIndex = 0;
- bool resolveNullValue;
//string? lastResolvedColumnName;
bool useAs = true;
- bool UseAs
+ public bool UseAs
{
get
{
@@ -116,7 +151,8 @@ bool UseAs
set => useAs = value;
}
- bool ResolveNullValue
+ bool resolveNullValue;
+ public bool ResolveNullValue
{
get
{
@@ -131,6 +167,14 @@ bool ResolveNullValue
}
bool isVisitConvert;
+ public bool IsVisitConvert
+ {
+ get => isVisitConvert;
+ set => isVisitConvert = value;
+ }
+
+ int parameterPositionIndex = 0;
+ public int ParameterPositionIndex { get => parameterPositionIndex; set => parameterPositionIndex = value; }
Expression? VisitLambda(LambdaExpression exp)
{
@@ -153,12 +197,13 @@ bool ResolveNullValue
// 数组访问
if (exp.NodeType == ExpressionType.ArrayIndex)
{
- var index = ExtractInstanceValue(exp.Right);
- var array = ExtractInstanceValue(exp.Left);
+ var index = ResolveHelper.ExtractInstanceValue(exp.Right);
+ var array = ResolveHelper.ExtractInstanceValue(exp.Left);
var arrayValue = array!.GetValue(index);
- var pname = FormatDbParameterName(Context, Options, $"Arr{index}", ref parameterPositionIndex);
+ var pname = ResolveHelper.FormatDbParameterName(Context, Options, $"Arr{index}", ref parameterPositionIndex);
Sql.Append(pname);
DbParameters.Add(new(pname, arrayValue, ExpValueType.Other));
+ ContainVariable = true;
return null;
}
if (Options.SqlType == SqlPartial.Where || Options.SqlType == SqlPartial.Join || Options.SqlType == SqlPartial.Select)
@@ -179,45 +224,7 @@ bool ResolveNullValue
return null;
- // 尝试将表达式求值为常量(仅支持 Constant 和 简单 Member 访问)
- static T ExtractInstanceValue(Expression expression)
- {
- if (expression is ConstantExpression ce && ce.Value is T index)
- {
- return index;
- }
- var members = new Stack();
- Expression? current = expression;
-
- // 向下遍历,收集 MemberInfo
- while (current is MemberExpression memberExpr)
- {
- members.Push(memberExpr.Member);
- current = memberExpr.Expression;
- }
- object? value;
-
- if (current is ConstantExpression constExpr)
- {
- value = constExpr.Value;
- }
- else if (current is null)
- {
- value = null;
- }
- else
- {
- throw new LightOrmException($"数组索引表达式必须以常量或者Null结尾,但得到: {current?.GetType().Name}: {current}");
- }
- value = GetValue(members, value);
-
- if (value is T t)
- {
- return t;
- }
- throw new LightOrmException($"尝试获取类型{typeof(T)}的值,实际类型: {value?.GetType()}");
- }
}
Expression? VisitConditional(ConditionalExpression exp)
@@ -307,7 +314,7 @@ static T ExtractInstanceValue(Expression expression)
{
Debug.WriteLineIf(ShowExpressionResolveDebugInfo, $"{Options.SqlAction} {Options.SqlType}: UnaryExpression: {exp}");
IsNot = exp.NodeType == ExpressionType.Not;
- isVisitConvert = exp.NodeType == ExpressionType.Convert;
+ IsVisitConvert = exp.NodeType == ExpressionType.Convert;
Visit(exp.Operand);
return null;
}
@@ -336,9 +343,9 @@ static T ExtractInstanceValue(Expression expression)
}
else
{
- if (isVisitConvert && Members.Count > 0)
+ if (IsVisitConvert && Members.Count > 0)
{
- isVisitConvert = false;
+ IsVisitConvert = false;
var member = Members.Pop();
var table = Context.GetTable(exp);
var col = table.GetColumn(member.Name)!;
@@ -467,10 +474,11 @@ static T ExtractInstanceValue(Expression expression)
{
//value = GetValue(Members, value, out var name);
//VariableValue(value, name);
- var v = GetValueByExpression(Members, value, out var propNames);
- var pn = FormatDbParameterName(Context, Options, propNames, ref parameterPositionIndex);
+ var v = ResolveHelper.GetValueByExpression(Members, value, out var propNames);
+ var pn = ResolveHelper.FormatDbParameterName(Context, Options, propNames, ref parameterPositionIndex);
Sql.Append(pn);
VariableValue(v, pn);
+ ContainVariable = true;
}
else
{
@@ -548,81 +556,61 @@ void ConstraintValue(object? v)
}
}
- public static string FormatDbParameterName(ResolveContext? context, SqlResolveOptions? option, string name, ref int index)
- {
- var p = $"{context?.ParameterPrefix}{name}_{option?.ParameterPartialIndex}_{index}";
- index += 1;
- return p;
- }
-
- ///
- /// 获取值
- ///
- /// 成员信息
- /// 编译器变量值
- /// 成员名称
- ///
- [Obsolete]
- public static object? GetValue(Stack memberInfos, object? compilerVar, out string memberName)
- {
- var names = new List();
- while (memberInfos.Count > 0)
- {
- var item = memberInfos.Pop();
- if (!item.Name.StartsWith("CS$<>8__locals"))
- {
- names.Add(item.Name);
- }
-
- compilerVar = GetValue(item, compilerVar);
- }
- memberName = string.Join("_", names);
- return compilerVar;
- }
- public static object? GetValue(Stack memberInfos, object? compilerVar) => GetValueByExpression(memberInfos, compilerVar, out _);
-
- ///
- /// 获取值
- ///
- /// 成员信息
- /// 对象
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [Obsolete]
- public static object? GetValue(MemberInfo memberInfo, object? obj)
- {
- return memberInfo switch
- {
- PropertyInfo prop => prop.GetValue(obj),
- FieldInfo field => field.GetValue(obj),
- _ => throw new NotSupportedException($"不支持获取 {memberInfo.MemberType} 类型值.")
- };
- }
-
- private static readonly ConcurrentDictionary> getterCache = [];
- public static object? GetValueByExpression(Stack memberInfos, object? value, out string name)
- {
- name = string.Join("_", memberInfos.Where(m => !m.Name.StartsWith("CS$<>8__locals")).Select(m => m.Name));
- if (value is null) return null;
- var type = value.GetType();
- var memberKey = $"{type.FullName}_{name}";
- var func = getterCache.GetOrAdd(memberKey, _ =>
- {
- return CreateGetter(type, memberInfos);
- });
- return func.Invoke(value);
- }
-
- private static Func