Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/版本日志.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# 版本功能更新记录

## v2026.08.26
- 🐞修复`ExecuteResult`中的DataReader重复Close
- 🐞修复实体映射处理匿名类型中的class类型
- 🛠重构`SqlExecutor`,将连接和事务管理提升到ExpressionContext中

## v2026.08.21
- 🛠重构Table生成配置,基类`TableOptions`保留公共配置,由各Provider派生各自的配置项
- ⚡️新增`StringBuilderPool`,一定程度上缓解GC和内存占用
Expand Down
16 changes: 16 additions & 0 deletions src/LightORM/ExceptionPolyfills.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,25 @@ public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpres
}
}

extension(ObjectDisposedException)
{
public static void ThrowIf(bool condition, object instance)
{
if (condition)
ThrowObjectDisposedException(instance);
}

}

[DoesNotReturn]
internal static void Throw(string? paramName) =>
throw new ArgumentNullException(paramName);

[DoesNotReturn]
internal static void ThrowObjectDisposedException(object? instance)
{
throw new ObjectDisposedException(instance?.GetType().FullName);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/LightORM/ExpressionSql/DbInitial.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace LightORM.ExpressionSql;

public class DbInitial(ISqlExecutor executor, IDatabaseTableHandler handler) : IDbInitial
public class DbInitial(SqlAdo executor, IDatabaseTableHandler handler) : IDbInitial
{
public IDbInitial CreateTable<T>(params T[]? datas)
{
Expand Down
6 changes: 4 additions & 2 deletions src/LightORM/ExpressionSql/DbInitialContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ namespace LightORM;

public abstract class DbInitialContext
{
//internal static MethodInfo InitializedMethod = typeof(ExpressionContext).GetMethod(nameof(ExpressionContext.Initialized))!;
public abstract void Initialized(IDbInitial db);
public virtual string DatabaseKey() => ConstString.Main;
public DbInfo? Info { get; set; }

internal void Check(ExpressionSqlOptions option)
{
var factory = new ConnectionFactory(option);
bool hasTable = true;
bool update = false;
var key = DatabaseKey();
if (!option.DatabaseProviders.TryGetValue(key, out var db))
{
throw new LightOrmException($"{key} not register");
}
using var executor = new SqlExecutor.SqlExecutor(db, new AdoInterceptor(option.Interceptors));
using var connection = factory.GetDatabaseConnection(key);
var executor = new SqlAdo(connection);
option.DatabaseHandlers.TryGetValue(key, out var handler);
if (handler is null)
{
Expand Down
10 changes: 5 additions & 5 deletions src/LightORM/ExpressionSql/ExpressionCoreSql.Tran.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ partial class ExpressionCoreSql : IExpressionContext
{
public ISingleScopedExpressionContext Use(IDatabaseProvider db)
{
// 确保Use之后,拿到的ISqlExecutor是对应的
var ado = new SqlExecutor.SqlExecutor(db, Options.PoolSize, new AdoInterceptor(Options.Interceptors));
return new SingleScopedExpressionCoreSql(ado, Options);

var connection = connectionFactory.GetDatabaseConnection(db);
return new SingleScopedExpressionCoreSql(connection, Options);
}

public ISingleScopedExpressionContext CreateScoped(string key)
{
Debug.WriteLine("CreateScoped");
var ado = (ISqlExecutor)executorProvider.GetSqlExecutor(key).Clone();
return new SingleScopedExpressionCoreSql(ado, Options);
var connection = connectionFactory.GetDatabaseConnection(key);
return new SingleScopedExpressionCoreSql(connection, Options);
}

public IScopedExpressionContext CreateScoped()
Expand Down
49 changes: 29 additions & 20 deletions src/LightORM/ExpressionSql/ExpressionCoreSql.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
using System.Threading;
using System.Collections.Concurrent;
using System.Threading;
using LightORM.DbStruct;

namespace LightORM.ExpressionSql;

internal sealed partial class ExpressionCoreSql(ExpressionSqlOptions option) : ExpressionCoreSqlBase, IExpressionContext
internal sealed partial class ExpressionCoreSql(ExpressionSqlOptions option) : ExpressionCoreSqlBase(option), IExpressionContext
{
public override ExpressionSqlOptions Options { get; } = option;
internal readonly SqlExecutorProvider executorProvider = new(option);
//private readonly ConcurrentDictionary<string, DatabaseConnection> connections = [];
private readonly ConnectionFactory connectionFactory = new(option);
public string Id { get; } = $"{Guid.NewGuid():N}";
public override ISqlExecutor Ado => executorProvider.GetSqlExecutor(Options.DefaultDbKey);

public ITransientExpressionContext SwitchDatabase(string key)
public override SqlAdo Ado => GetAdo(Options.DefaultDbKey);
public TransientExpressionContext SwitchDatabase(string key)
{
var ado = executorProvider.GetSqlExecutor(key);
return TransientExpressionCoreSql.Create(key, ado, Options);
var connection = connectionFactory.GetDatabaseConnection(key);
return new(this, connection, Options);
}

public ISqlExecutor GetAdo(string key) => executorProvider.GetSqlExecutor(key);
public SqlAdo GetAdo(string key)
{
var connection = connectionFactory.GetDatabaseConnection(key);
return new(connection);
}

public IExpSelect Select(string tableName) => throw new NotImplementedException(); //new SelectProvider0(tableName, Ado);


private bool disposedValue;

private void Dispose(bool disposing)
Expand All @@ -30,7 +33,10 @@ private void Dispose(bool disposing)
if (disposing)
{
System.Diagnostics.Debug.WriteLine($"释放ExpressionCoreSql:{DateTime.Now}");
executorProvider.Dispose();
//foreach (var item in connections.Values)
//{
// item.Dispose();
//}
}

disposedValue = true;
Expand All @@ -45,25 +51,28 @@ public void Dispose()

public string? CreateTableSql<T>(IDatabaseProvider provider, Action<TableOptions>? action = null)
{
using var ado = new SqlExecutor.SqlExecutor(provider, Options.PoolSize, new(Options.Interceptors));
return InternalCreateTableSql<T>(ado, Options, action);
return ExpressionCoreSqlContextMethodImpl.InternalCreateTableSql<T>(provider, action);
}

public async Task<bool> CreateTableAsync<T>(IDatabaseProvider provider, Action<TableOptions>? action = null, CancellationToken cancellationToken = default)
{
using var ado = new SqlExecutor.SqlExecutor(provider, Options.PoolSize, new(Options.Interceptors));
return await InternalCreateTableAsync<T>(ado, Options, action, cancellationToken);
using var connection = connectionFactory.GetDatabaseConnection(provider);
var ado = new SqlAdo(connection);
var flag = await ExpressionCoreSqlContextMethodImpl.InternalCreateTableAsync<T>(ado, Options, action, cancellationToken);
return flag;
}

public async Task<IList<DbStruct.ReadedTable>> GetTablesAsync(IDatabaseProvider provider)
{
using var ado = new SqlExecutor.SqlExecutor(provider, Options.PoolSize, new(Options.Interceptors));
return await InternalGetTablesAsync(ado, Options);
using var connection = connectionFactory.GetDatabaseConnection(provider);
var ado = new SqlAdo(connection);
return await ExpressionCoreSqlContextMethodImpl.InternalGetTablesAsync(ado, Options);
}

public async Task<ReadedTable> GetTableStructAsync(IDatabaseProvider provider, DbStruct.ReadedTable table)
{
using var ado = new SqlExecutor.SqlExecutor(provider, Options.PoolSize, new(Options.Interceptors));
return await InternalTableStructAsync(table, ado, Options);
using var connection = connectionFactory.GetDatabaseConnection(provider);
var ado = new SqlAdo(connection);
return await ExpressionCoreSqlContextMethodImpl.InternalTableStructAsync(table, ado, Options);
}
}
Loading
Loading