Parcourir la source

# 2.4.0
- [Vitorm] DbContext, new method GetEntityDescriptorFromCache
- [Vitorm] move BeginTransaction to interface and refactor Transaction
- [Vitorm] rename GetCurrentTransaction to GetDbTransaction

Lith il y a 4 mois
Parent
commit
16cd00f04f

+ 6 - 0
doc/ReleaseNotes.md

@@ -1,5 +1,11 @@
 # Vitorm ReleaseNotes
 
+-----------------------
+# 2.4.0
+- [Vitorm] DbContext, new method GetEntityDescriptorFromCache
+- [Vitorm] move BeginTransaction to interface and refactor Transaction
+- [Vitorm] rename GetCurrentTransaction to GetDbTransaction
+
 -----------------------
 # 2.3.0
 

+ 1 - 1
src/Versions.props

@@ -1,6 +1,6 @@
 <Project>
     <PropertyGroup>
-        <Version>2.3.0</Version>
+        <Version>2.4.0</Version>
         <VitLinq_Version>[3.1.5, 3.2.0)</VitLinq_Version>
     </PropertyGroup>
 

+ 4 - 4
src/Vitorm.MySql/DbContext_Extensions_UseMySql.cs

@@ -2,7 +2,7 @@
 
 using Vitorm.MySql;
 using Vitorm.Sql;
-using Vitorm.Sql.Transaction;
+using Vitorm.Transaction;
 
 using DbConnection = MySqlConnector.MySqlConnection;
 
@@ -21,7 +21,7 @@ namespace Vitorm
                 sqlExecutor: sqlExecutor
                 );
 
-            dbContext.createTransactionScope = createTransactionScope;
+            dbContext.createTransactionManager = createTransactionManager;
 
 
             if (config.commandTimeout.HasValue) dbContext.commandTimeout = config.commandTimeout.Value;
@@ -44,8 +44,8 @@ namespace Vitorm
         #endregion
 
 
-        static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.MySql.SqlTransactionScope(dbContext);
-        //static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.MySql.SqlTransactionScope_Command(dbContext);
+        static ITransactionManager createTransactionManager(SqlDbContext dbContext) => new Vitorm.MySql.SqlTransactionManager(dbContext);
+        static ITransactionManager createTransactionManager2(SqlDbContext dbContext) => new Vitorm.MySql.SqlTransactionManager_Command(dbContext);
 
 
     }

+ 12 - 11
src/Vitorm.MySql/SqlTransactionScope.cs → src/Vitorm.MySql/SqlTransactionManager.cs

@@ -2,27 +2,28 @@
 
 using Vitorm.Sql;
 using Vitorm.Sql.Transaction;
+using Vitorm.Transaction;
 
 using SqlTransaction = MySqlConnector.MySqlTransaction;
 
 namespace Vitorm.MySql
 {
-    public class SqlTransactionScope : Vitorm.Sql.Transaction.SqlTransactionScope
+    public class SqlTransactionManager : Vitorm.Sql.Transaction.SqlTransactionManager
     {
         int savePointCount = 0;
-        public DbTransactionWrap CreateTransactionSavePoint(IDbTransaction originalTransaction)
+        public Sql.Transaction.SqlTransaction CreateTransactionSavePoint(IDbTransaction originalTransaction)
         {
             var savePointName = "tran" + savePointCount++;
             return new DbTransactionWrapSavePoint(originalTransaction, savePointName);
         }
-        public SqlTransactionScope(SqlDbContext dbContext) : base(dbContext)
+        public SqlTransactionManager(SqlDbContext dbContext) : base(dbContext)
         {
         }
 
-        public override IDbTransaction BeginTransaction()
+        public override ITransaction BeginTransaction()
         {
-            DbTransactionWrap transactionWrap;
-            IDbTransaction originalTransaction = GetCurrentTransaction();
+            Sql.Transaction.SqlTransaction transaction;
+            IDbTransaction originalTransaction = GetDbTransaction();
             if (originalTransaction == null)
             {
                 var dbConnection = dbContext.dbConnection as MySqlConnector.MySqlConnection;
@@ -30,20 +31,20 @@ namespace Vitorm.MySql
 
                 originalTransaction = dbConnection.BeginTransaction();
                 dbContext.ExecuteWithTransaction("SET autocommit=0;", transaction: originalTransaction);
-                transactionWrap = new DbTransactionWrap(originalTransaction);
+                transaction = new Sql.Transaction.SqlTransaction(originalTransaction);
             }
             else
             {
-                transactionWrap = CreateTransactionSavePoint(originalTransaction);
+                transaction = CreateTransactionSavePoint(originalTransaction);
             }
 
-            transactions.Push(transactionWrap);
-            return transactionWrap;
+            transactions.Push(transaction);
+            return transaction;
         }
 
 
 
-        public class DbTransactionWrapSavePoint : DbTransactionWrap
+        public class DbTransactionWrapSavePoint : Sql.Transaction.SqlTransaction
         {
             public SqlTransaction sqlTran => (SqlTransaction)originalTransaction;
             readonly string savePointName;

+ 19 - 22
src/Vitorm.MySql/SqlTransactionScope_Command.cs → src/Vitorm.MySql/SqlTransactionManager_Command.cs

@@ -3,8 +3,8 @@ using System.Data;
 
 using Vitorm.Sql;
 using Vitorm.Sql.Transaction;
+using Vitorm.Transaction;
 
-using static Vitorm.Sql.Transaction.DbTransactionWrap;
 
 namespace Vitorm.MySql
 {
@@ -21,63 +21,60 @@ namespace Vitorm.MySql
           COMMIT;
           -- ROLLBACK;
     */
-    public class SqlTransactionScope_Command : ITransactionScope
+    public class SqlTransactionManager_Command : ITransactionManager
     {
         protected SqlDbContext dbContext;
-        protected Stack<DbTransactionWrapSavePoint> savePoints = new();
+        protected Stack<TransactionSavePoint> savePoints = new();
         int savePointCount = 0;
-        public SqlTransactionScope_Command(SqlDbContext dbContext)
+        public SqlTransactionManager_Command(SqlDbContext dbContext)
         {
             this.dbContext = dbContext;
         }
 
-        DbTransactionWrap_Command dbTransactionWrap;
-        public virtual IDbTransaction BeginTransaction()
+        Transaction_Command transaction;
+        public virtual ITransaction BeginTransaction()
         {
-            if (dbTransactionWrap == null)
+            if (transaction == null)
             {
                 var dbConnection = dbContext.dbConnection;
                 if (dbConnection.State != ConnectionState.Open) dbConnection.Open();
 
-                dbTransactionWrap = new DbTransactionWrap_Command(dbContext);
-                return dbTransactionWrap;
+                transaction = new Transaction_Command(dbContext);
+                return transaction;
 
             }
             var savePointName = "tran" + savePointCount++;
-            var savePoint = dbTransactionWrap.BeginSavePoint(savePointName);
+            var savePoint = transaction.BeginSavePoint(savePointName);
 
             savePoints.Push(savePoint);
             return savePoint;
         }
-
-        public virtual IDbTransaction GetCurrentTransaction() => null;
-
         public virtual void Dispose()
         {
             while (savePoints?.Count > 0)
             {
                 var transaction = savePoints.Pop();
-                if (transaction?.TransactionState != DbTransactionWrap.ETransactionState.Disposed)
+                if (transaction?.TransactionState != ETransactionState.Disposed)
                 {
                     transaction?.Dispose();
                 }
             }
             savePoints = null;
 
-            dbTransactionWrap?.Dispose();
-            dbTransactionWrap = null;
+            transaction?.Dispose();
+            transaction = null;
         }
 
 
 
-        public class DbTransactionWrap_Command : IDbTransaction
+        public class Transaction_Command : ITransaction
         {
             public virtual System.Data.IsolationLevel IsolationLevel => default;
             public IDbConnection Connection => dbContext.dbConnection;
             readonly SqlDbContext dbContext;
             public virtual ETransactionState TransactionState { get; protected set; } = ETransactionState.Active;
 
-            public DbTransactionWrap_Command(SqlDbContext dbContext)
+            public Transaction_Command(SqlDbContext dbContext)
             {
                 this.dbContext = dbContext;
                 Execute($"START TRANSACTION; SET autocommit=0;");
@@ -103,9 +100,9 @@ namespace Vitorm.MySql
                 Execute($"ROLLBACK;");
                 TransactionState = ETransactionState.RolledBack;
             }
-            public DbTransactionWrapSavePoint BeginSavePoint(string savePoint)
+            public TransactionSavePoint BeginSavePoint(string savePoint)
             {
-                return new DbTransactionWrapSavePoint(dbContext, savePoint);
+                return new TransactionSavePoint(dbContext, savePoint);
             }
             protected virtual void Execute(string sql)
             {
@@ -113,7 +110,7 @@ namespace Vitorm.MySql
             }
         }
 
-        public class DbTransactionWrapSavePoint : IDbTransaction
+        public class TransactionSavePoint : ITransaction
         {
             public virtual System.Data.IsolationLevel IsolationLevel => default;
 
@@ -127,7 +124,7 @@ namespace Vitorm.MySql
             {
                 dbContext.ExecuteWithTransaction(sql);
             }
-            public DbTransactionWrapSavePoint(SqlDbContext dbContext, string savePointName)
+            public TransactionSavePoint(SqlDbContext dbContext, string savePointName)
             {
                 this.dbContext = dbContext;
                 this.savePointName = savePointName;

+ 3 - 3
src/Vitorm.SqlServer/DbContext_Extensions_UseSqlServer.cs

@@ -1,6 +1,6 @@
 using Vitorm.Sql;
-using Vitorm.Sql.Transaction;
 using Vitorm.SqlServer;
+using Vitorm.Transaction;
 
 namespace Vitorm
 {
@@ -16,14 +16,14 @@ namespace Vitorm
                 dbConnectionProvider: config.ToDbConnectionProvider()
                 );
 
-            dbContext.createTransactionScope = createTransactionScope;
+            dbContext.createTransactionManager = createTransactionManager;
 
             if (config.commandTimeout.HasValue) dbContext.commandTimeout = config.commandTimeout.Value;
 
             return dbContext;
         }
 
-        static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.SqlServer.SqlTransactionScope(dbContext);
+        static ITransactionManager createTransactionManager(SqlDbContext dbContext) => new Vitorm.SqlServer.SqlTransactionManager(dbContext);
 
     }
 }

+ 14 - 13
src/Vitorm.SqlServer/SqlTransactionScope.cs → src/Vitorm.SqlServer/SqlTransactionManager.cs

@@ -2,51 +2,52 @@
 
 using Vitorm.Sql;
 using Vitorm.Sql.Transaction;
+using Vitorm.Transaction;
 
 using SqlTransaction = Microsoft.Data.SqlClient.SqlTransaction;
 
 namespace Vitorm.SqlServer
 {
-    public class SqlTransactionScope : Vitorm.Sql.Transaction.SqlTransactionScope
+    public class SqlTransactionManager : Vitorm.Sql.Transaction.SqlTransactionManager
     {
         int savePointCount = 0;
-        public DbTransactionWrap CreateTransactionSavePoint(IDbTransaction originalTransaction)
+        public Sql.Transaction.SqlTransaction CreateTransactionSavePoint(IDbTransaction originalTransaction)
         {
             var savePointName = "tran" + savePointCount++;
-            return new DbTransactionWrapSavePoint(originalTransaction, savePointName);
+            return new TransactionSavePoint(originalTransaction, savePointName);
         }
-        public SqlTransactionScope(SqlDbContext dbContext) : base(dbContext)
+        public SqlTransactionManager(SqlDbContext dbContext) : base(dbContext)
         {
         }
 
-        public override IDbTransaction BeginTransaction()
+        public override ITransaction BeginTransaction()
         {
-            DbTransactionWrap transactionWrap;
-            IDbTransaction originalTransaction = GetCurrentTransaction();
+            Sql.Transaction.SqlTransaction transaction;
+            IDbTransaction originalTransaction = GetDbTransaction();
             if (originalTransaction == null)
             {
                 var dbConnection = dbContext.dbConnection;
                 if (dbConnection.State != ConnectionState.Open) dbConnection.Open();
                 originalTransaction = dbConnection.BeginTransaction();
 
-                transactionWrap = new DbTransactionWrap(originalTransaction);
+                transaction = new Sql.Transaction.SqlTransaction(originalTransaction);
             }
             else
             {
-                transactionWrap = CreateTransactionSavePoint(originalTransaction);
+                transaction = CreateTransactionSavePoint(originalTransaction);
             }
 
-            transactions.Push(transactionWrap);
-            return transactionWrap;
+            transactions.Push(transaction);
+            return transaction;
         }
 
     }
 
-    public class DbTransactionWrapSavePoint : DbTransactionWrap
+    public class TransactionSavePoint : Sql.Transaction.SqlTransaction
     {
         public SqlTransaction sqlTran => (SqlTransaction)originalTransaction;
         readonly string savePointName;
-        public DbTransactionWrapSavePoint(IDbTransaction transaction, string savePointName) : base(transaction)
+        public TransactionSavePoint(IDbTransaction transaction, string savePointName) : base(transaction)
         {
             this.savePointName = savePointName;
             sqlTran.Save(savePointName);

+ 3 - 3
src/Vitorm.Sqlite/DbContext_Extensions_UseSqlite.cs

@@ -1,6 +1,6 @@
 using Vitorm.Sql;
-using Vitorm.Sql.Transaction;
 using Vitorm.Sqlite;
+using Vitorm.Transaction;
 
 namespace Vitorm
 {
@@ -16,13 +16,13 @@ namespace Vitorm
                 dbConnectionProvider: config.ToDbConnectionProvider()
                 );
 
-            dbContext.createTransactionScope = createTransactionScope;
+            dbContext.createTransactionManager = createTransactionManager;
 
             if (config.commandTimeout.HasValue) dbContext.commandTimeout = config.commandTimeout.Value;
 
             return dbContext;
         }
 
-        static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.Sqlite.SqlTransactionScope(dbContext);
+        static ITransactionManager createTransactionManager(SqlDbContext dbContext) => new Vitorm.Sqlite.SqlTransactionManager(dbContext);
     }
 }

+ 14 - 13
src/Vitorm.Sqlite/SqlTransactionScope.cs → src/Vitorm.Sqlite/SqlTransactionManager.cs

@@ -2,52 +2,53 @@
 
 using Vitorm.Sql;
 using Vitorm.Sql.Transaction;
+using Vitorm.Transaction;
 
 using SqlTransaction = Microsoft.Data.Sqlite.SqliteTransaction;
 
 namespace Vitorm.Sqlite
 {
     // sqlite/transactions  https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/transactions  
-    public class SqlTransactionScope : Vitorm.Sql.Transaction.SqlTransactionScope
+    public class SqlTransactionManager : Vitorm.Sql.Transaction.SqlTransactionManager
     {
         int savePointCount = 0;
-        public DbTransactionWrap CreateTransactionSavePoint(IDbTransaction originalTransaction)
+        public Sql.Transaction.SqlTransaction CreateTransactionSavePoint(IDbTransaction originalTransaction)
         {
             var savePointName = "tran" + savePointCount++;
-            return new DbTransactionWrapSavePoint(originalTransaction, savePointName);
+            return new TransactionSavePoint(originalTransaction, savePointName);
         }
-        public SqlTransactionScope(SqlDbContext dbContext) : base(dbContext)
+        public SqlTransactionManager(SqlDbContext dbContext) : base(dbContext)
         {
         }
 
-        public override IDbTransaction BeginTransaction()
+        public override ITransaction BeginTransaction()
         {
-            DbTransactionWrap transactionWrap;
-            IDbTransaction originalTransaction = GetCurrentTransaction();
+            Sql.Transaction.SqlTransaction transaction;
+            IDbTransaction originalTransaction = GetDbTransaction();
             if (originalTransaction == null)
             {
                 var dbConnection = dbContext.dbConnection;
                 if (dbConnection.State != ConnectionState.Open) dbConnection.Open();
                 originalTransaction = dbConnection.BeginTransaction();
 
-                transactionWrap = new DbTransactionWrap(originalTransaction);
+                transaction = new Sql.Transaction.SqlTransaction(originalTransaction);
             }
             else
             {
-                transactionWrap = CreateTransactionSavePoint(originalTransaction);
+                transaction = CreateTransactionSavePoint(originalTransaction);
             }
 
-            transactions.Push(transactionWrap);
-            return transactionWrap;
+            transactions.Push(transaction);
+            return transaction;
         }
 
     }
 
-    public class DbTransactionWrapSavePoint : DbTransactionWrap
+    public class TransactionSavePoint : Sql.Transaction.SqlTransaction
     {
         public SqlTransaction sqlTran => (SqlTransaction)originalTransaction;
         readonly string savePointName;
-        public DbTransactionWrapSavePoint(IDbTransaction transaction, string savePointName) : base(transaction)
+        public TransactionSavePoint(IDbTransaction transaction, string savePointName) : base(transaction)
         {
             this.savePointName = savePointName;
             sqlTran.Save(savePointName);

+ 20 - 0
src/Vitorm/DbContext.Transaction.cs

@@ -0,0 +1,20 @@
+using System;
+
+using Vitorm.Transaction;
+
+namespace Vitorm
+{
+    public partial class DbContext : IDbContext, IDisposable
+    {
+        #region Transaction
+
+        public virtual ITransaction BeginTransaction()
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+
+
+}

+ 5 - 0
src/Vitorm/DbContext.cs

@@ -66,6 +66,11 @@ namespace Vitorm
             if (tryFromCache && dbSetMap?.TryGetValue(entityType, out var dbSet) == true) return dbSet.entityDescriptor;
             return entityLoader.LoadDescriptor(entityType).entityDescriptor;
         }
+        public virtual IEntityDescriptor GetEntityDescriptorFromCache(Type entityType)
+        {
+            if (dbSetMap?.TryGetValue(entityType, out var dbSet) == true) return dbSet.entityDescriptor;
+            return default;
+        }
         public virtual IEntityDescriptor GetEntityDescriptor<Entity>(bool tryFromCache = true)
             => GetEntityDescriptor(typeof(Entity), tryFromCache);
         #endregion

+ 1 - 0
src/Vitorm/IDbContext.cs

@@ -6,6 +6,7 @@ namespace Vitorm
 {
     public partial interface IDbContext
     {
+
         #region Sync Method
 
         // #0 Schema :  Create Drop

+ 16 - 15
src/Vitorm/Sql/SqlDbContext.Execute.cs

@@ -4,6 +4,7 @@ using System.Data;
 using System.Threading.Tasks;
 
 using Vitorm.Sql.Transaction;
+using Vitorm.Transaction;
 
 namespace Vitorm.Sql
 {
@@ -13,11 +14,11 @@ namespace Vitorm.Sql
         {
             try
             {
-                transactionScope?.Dispose();
+                transactionManager?.Dispose();
             }
             finally
             {
-                transactionScope = null;
+                transactionManager = null;
                 try
                 {
                     _dbConnection?.Dispose();
@@ -80,16 +81,16 @@ namespace Vitorm.Sql
 
 
         #region Transaction
-        public virtual Func<SqlDbContext, ITransactionScope> createTransactionScope { set; get; }
-                    = (dbContext) => new SqlTransactionScope(dbContext);
-        protected virtual ITransactionScope transactionScope { get; set; }
+        public virtual Func<SqlDbContext, ITransactionManager> createTransactionManager { set; get; }
+                    = (dbContext) => new SqlTransactionManager(dbContext);
+        protected virtual ITransactionManager transactionManager { get; set; }
 
-        public virtual IDbTransaction BeginTransaction()
+        public override ITransaction BeginTransaction()
         {
-            transactionScope ??= createTransactionScope(this);
-            return transactionScope.BeginTransaction();
+            transactionManager ??= createTransactionManager(this);
+            return transactionManager.BeginTransaction();
         }
-        public virtual IDbTransaction GetCurrentTransaction() => transactionScope?.GetCurrentTransaction();
+        public virtual IDbTransaction GetDbTransaction() => (transactionManager as SqlTransactionManager)?.GetDbTransaction();
 
         #endregion
 
@@ -108,7 +109,7 @@ namespace Vitorm.Sql
             this.Event_OnExecuting(sql, param);
 
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            var transaction = GetCurrentTransaction();
+            var transaction = GetDbTransaction();
 
             if (useReadOnly && transaction == null)
             {
@@ -125,7 +126,7 @@ namespace Vitorm.Sql
             this.Event_OnExecuting(sql, param);
 
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            var transaction = GetCurrentTransaction();
+            var transaction = GetDbTransaction();
 
             if (useReadOnly && transaction == null)
             {
@@ -142,7 +143,7 @@ namespace Vitorm.Sql
             this.Event_OnExecuting(sql, param);
 
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            var transaction = GetCurrentTransaction();
+            var transaction = GetDbTransaction();
 
             if (useReadOnly && transaction == null)
             {
@@ -170,7 +171,7 @@ namespace Vitorm.Sql
         public virtual async Task<int> ExecuteAsync(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
         {
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            var transaction = GetCurrentTransaction();
+            var transaction = GetDbTransaction();
 
             if (useReadOnly && transaction == null)
             {
@@ -185,7 +186,7 @@ namespace Vitorm.Sql
         public virtual async Task<IDataReader> ExecuteReaderAsync(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
         {
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            var transaction = GetCurrentTransaction();
+            var transaction = GetDbTransaction();
 
             if (useReadOnly && transaction == null)
             {
@@ -200,7 +201,7 @@ namespace Vitorm.Sql
         public virtual async Task<object> ExecuteScalarAsync(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
         {
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            var transaction = GetCurrentTransaction();
+            var transaction = GetDbTransaction();
 
             if (useReadOnly && transaction == null)
             {

+ 3 - 6
src/Vitorm/Sql/SqlTranslate/QueryTranslateService.cs

@@ -46,16 +46,13 @@ namespace Vitorm.Sql.SqlTranslate
                     }
                 case nameof(Queryable.FirstOrDefault) or nameof(Queryable.First) or nameof(Queryable.LastOrDefault) or nameof(Queryable.Last):
                     {
-                        if (stream.skip.HasValue)
+                        if (stream.method.Contains("Last"))
                         {
-                            if (stream.method.Contains("Last"))
+                            if (stream.skip.HasValue)
                             {
                                 stream.skip = stream.skip.Value + (stream.take ?? 0) - 1;
                             }
-                        }
-                        else
-                        {
-                            if (stream.method.Contains("Last"))
+                            else
                             {
                                 ReverseOrder(arg, stream);
                             }

+ 8 - 0
src/Vitorm/Sql/Transaction/ETransactionState.cs

@@ -0,0 +1,8 @@
+namespace Vitorm.Sql.Transaction
+{
+    public enum ETransactionState
+    {
+        Active, Committed, RolledBack, Disposed
+    }
+
+}

+ 0 - 11
src/Vitorm/Sql/Transaction/ITransactionScope.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Data;
-
-namespace Vitorm.Sql.Transaction
-{
-    public interface ITransactionScope : IDisposable
-    {
-        IDbTransaction BeginTransaction();
-        IDbTransaction GetCurrentTransaction();
-    }
-}

+ 6 - 8
src/Vitorm/Sql/Transaction/DbTransactionWrap.cs → src/Vitorm/Sql/Transaction/SqlTransaction.cs

@@ -1,23 +1,21 @@
 using System.Data;
 
+using Vitorm.Transaction;
+
 namespace Vitorm.Sql.Transaction
 {
-    public class DbTransactionWrap : IDbTransaction
+    public partial class SqlTransaction : ITransaction
     {
-        public enum ETransactionState
-        {
-            Active, Committed, RolledBack, Disposed
-        }
         public virtual ETransactionState TransactionState { get; protected set; } = ETransactionState.Active;
-        public DbTransactionWrap(IDbTransaction transaction)
+        public SqlTransaction(IDbTransaction transaction)
         {
             originalTransaction = transaction;
         }
         public IDbTransaction originalTransaction;
 
-        public virtual IDbConnection Connection => originalTransaction.Connection;
+        //public virtual IDbConnection Connection => originalTransaction.Connection;
 
-        public virtual System.Data.IsolationLevel IsolationLevel => originalTransaction.IsolationLevel;
+        //public virtual System.Data.IsolationLevel IsolationLevel => originalTransaction.IsolationLevel;
 
         public virtual void Commit()
         {

+ 12 - 10
src/Vitorm/Sql/Transaction/SqlTransactionScope.cs → src/Vitorm/Sql/Transaction/SqlTransactionManager.cs

@@ -1,28 +1,30 @@
 using System.Collections.Generic;
 using System.Data;
 
+using Vitorm.Transaction;
+
 namespace Vitorm.Sql.Transaction
 {
-    public class SqlTransactionScope : ITransactionScope
+    public class SqlTransactionManager : ITransactionManager
     {
-        public SqlTransactionScope(SqlDbContext dbContext)
+        public SqlTransactionManager(SqlDbContext dbContext)
         {
             this.dbContext = dbContext;
         }
 
         protected SqlDbContext dbContext;
-        protected Stack<DbTransactionWrap> transactions = new();
+        protected Stack<SqlTransaction> transactions = new();
 
 
-        public virtual IDbTransaction BeginTransaction()
+        public virtual ITransaction BeginTransaction()
         {
             var dbConnection = dbContext.dbConnection;
             if (dbConnection.State != ConnectionState.Open) dbConnection.Open();
             var transaction = dbConnection.BeginTransaction();
 
-            var transactionWrap = new DbTransactionWrap(transaction);
-            transactions.Push(transactionWrap);
-            return transactionWrap;
+            var sqlTransaction = new SqlTransaction(transaction);
+            transactions.Push(sqlTransaction);
+            return sqlTransaction;
         }
 
         public virtual void Dispose()
@@ -30,7 +32,7 @@ namespace Vitorm.Sql.Transaction
             while (transactions?.Count > 0)
             {
                 var transaction = transactions.Pop();
-                if (transaction?.TransactionState != DbTransactionWrap.ETransactionState.Disposed)
+                if (transaction?.TransactionState != ETransactionState.Disposed)
                 {
                     transaction?.Dispose();
                 }
@@ -38,12 +40,12 @@ namespace Vitorm.Sql.Transaction
             transactions = null;
         }
 
-        public virtual IDbTransaction GetCurrentTransaction()
+        public virtual IDbTransaction GetDbTransaction()
         {
             while (transactions?.Count > 0)
             {
                 var tran = transactions.Peek();
-                if (tran?.TransactionState == DbTransactionWrap.ETransactionState.Active) return tran.originalTransaction;
+                if (tran?.TransactionState == ETransactionState.Active) return tran.originalTransaction;
                 transactions.Pop();
             }
             return null;

+ 10 - 0
src/Vitorm/Transaction/ITransaction.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace Vitorm.Transaction
+{
+    public interface ITransaction : IDisposable
+    {
+        void Commit();
+        void Rollback();
+    }
+}

+ 9 - 0
src/Vitorm/Transaction/ITransactionManager.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace Vitorm.Transaction
+{
+    public interface ITransactionManager : IDisposable
+    {
+        ITransaction BeginTransaction();
+    }
+}

+ 1 - 1
src/Vitorm/TypeUtil.cs

@@ -37,7 +37,7 @@ namespace Vitorm
         public static bool IsArrayType(Type type)
         {
             if (type.IsArray) return true;
-            if (type.IsGenericType && typeof(ICollection).IsAssignableFrom(type)) return true;
+            if (type.IsGenericType && typeof(IEnumerable).IsAssignableFrom(type)) return true;
             return false;
         }
 

+ 56 - 0
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Group_FirstOrDefault_Test.cs

@@ -0,0 +1,56 @@
+using System.Data;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+
+namespace Vitorm.MsTest.CommonTest
+{
+    [TestClass]
+    public class Query_Group_FirstOrDefault_Test
+    {
+
+        [TestMethod]
+        public void Test_Group_FirstOrDefault()
+        {
+            using var dbContext = DataSource.CreateDbContext();
+            var userQuery = dbContext.Query<User>();
+
+            // Linq Expression
+            {
+                var query =
+                        from user in userQuery
+                        where user.fatherId != null
+                        group user by new { user.fatherId, user.motherId } into userGroup
+                        orderby userGroup.Key.fatherId, userGroup.Key.motherId
+                        select new { userGroup.Key.fatherId, userGroup.Key.motherId };
+
+                var row = query.FirstOrDefault();
+
+                Assert.AreEqual(4, row?.fatherId);
+                Assert.AreEqual(6, row?.motherId);
+            }
+
+            // Lambda Expression
+            {
+                var query =
+                        userQuery.Where(m => m.fatherId != null)
+                        .GroupBy(user => new { user.fatherId, user.motherId })
+                        .OrderBy(userGroup => userGroup.Key.fatherId).ThenBy(userGroup => userGroup.Key.motherId)
+                        .Select(userGroup => new
+                        {
+                            userGroup.Key.fatherId,
+                            userGroup.Key.motherId
+                        })
+                        ;
+
+                var row = query.FirstOrDefault();
+
+                Assert.AreEqual(4, row?.fatherId);
+                Assert.AreEqual(6, row?.motherId);
+            }
+        }
+
+
+
+    }
+}

+ 54 - 0
test/Vitorm.Sqlite.MsTest/CommonTest/Transaction_Nested_Test.cs

@@ -0,0 +1,54 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Vitorm.MsTest.CommonTest
+{
+
+    [TestClass]
+    public class Transaction_Nested_Test
+    {
+
+        [TestMethod]
+        public void Test_NestedTransaction()
+        {
+            {
+                using var dbContext = DataSource.CreateDbContext();
+                var userSet = dbContext.DbSet<User>();
+
+                Assert.AreEqual("u400", userSet.Get(4).name);
+
+                using (var tran1 = dbContext.BeginTransaction())
+                {
+                    dbContext.Update(new User { id = 4, name = "u4001" });
+                    Assert.AreEqual("u4001", userSet.Get(4).name);
+
+                    using (var tran2 = dbContext.BeginTransaction())
+                    {
+                        dbContext.Update(new User { id = 4, name = "u4002" });
+                        Assert.AreEqual("u4002", userSet.Get(4).name);
+                    }
+                    Assert.AreEqual("u4001", userSet.Get(4).name);
+
+                    using (var tran2 = dbContext.BeginTransaction())
+                    {
+                        dbContext.Update(new User { id = 4, name = "u4002" });
+                        Assert.AreEqual("u4002", userSet.Get(4).name);
+                        tran2.Rollback();
+                    }
+                    Assert.AreEqual("u4001", userSet.Get(4).name);
+
+                    using (var tran2 = dbContext.BeginTransaction())
+                    {
+                        dbContext.Update(new User { id = 4, name = "u4003" });
+                        Assert.AreEqual("u4003", userSet.Get(4).name);
+                        tran2.Commit();
+                    }
+                    Assert.AreEqual("u4003", userSet.Get(4).name);
+                }
+
+                Assert.AreEqual("u400", userSet.Get(4).name);
+            }
+        }
+
+
+    }
+}

+ 4 - 46
test/Vitorm.Sqlite.MsTest/CommonTest/Transaction_Test.cs

@@ -48,8 +48,7 @@ namespace Vitorm.MsTest.CommonTest
         }
 
 
-        // can not test for db is not durable
-        //[TestMethod]
+        [TestMethod]
         public void Test_Dispose()
         {
             {
@@ -72,58 +71,17 @@ namespace Vitorm.MsTest.CommonTest
                 }
                 Assert.AreEqual("u4003", userSet.Get(4).name);
             }
+
             {
-                using var dbContext = DataSource.CreateDbContext();
+                using var dbContext = DataSource.CreateDbContext(autoInit: false);
                 var userSet = dbContext.DbSet<User>();
 
-                //Assert.AreEqual("u4002", userSet.Get(4).name);
+                Assert.AreEqual("u4002", userSet.Get(4).name);
             }
 
         }
 
-        [TestMethod]
-        public void Test_NestedTransaction()
-        {
-            #region NestedTransaction
-            {
-                using var dbContext = DataSource.CreateDbContext();
-                var userSet = dbContext.DbSet<User>();
 
-                Assert.AreEqual("u400", userSet.Get(4).name);
-
-                using (var tran1 = dbContext.BeginTransaction())
-                {
-                    dbContext.Update(new User { id = 4, name = "u4001" });
-                    Assert.AreEqual("u4001", userSet.Get(4).name);
-
-                    using (var tran2 = dbContext.BeginTransaction())
-                    {
-                        dbContext.Update(new User { id = 4, name = "u4002" });
-                        Assert.AreEqual("u4002", userSet.Get(4).name);
-                    }
-                    Assert.AreEqual("u4001", userSet.Get(4).name);
-
-                    using (var tran2 = dbContext.BeginTransaction())
-                    {
-                        dbContext.Update(new User { id = 4, name = "u4002" });
-                        Assert.AreEqual("u4002", userSet.Get(4).name);
-                        tran2.Rollback();
-                    }
-                    Assert.AreEqual("u4001", userSet.Get(4).name);
-
-                    using (var tran2 = dbContext.BeginTransaction())
-                    {
-                        dbContext.Update(new User { id = 4, name = "u4003" });
-                        Assert.AreEqual("u4003", userSet.Get(4).name);
-                        tran2.Commit();
-                    }
-                    Assert.AreEqual("u4003", userSet.Get(4).name);
-                }
-
-                Assert.AreEqual("u400", userSet.Get(4).name);
-            }
-            #endregion
-        }
 
 
 

+ 1 - 2
test/Vitorm.Sqlite.MsTest/DataSource.cs

@@ -62,8 +62,7 @@ namespace Vitorm.MsTest
         public static SqlDbContext CreateDbContextForWriting(bool autoInit = true) => CreateDbContext(autoInit);
         public static SqlDbContext CreateDbContext(bool autoInit = true)
         {
-            var guid = Guid.NewGuid().ToString();
-            var filePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, $"{guid}.sqlite.db");
+            var filePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, $"db_orm.sqlite.db");
             var connectionString = $"data source={filePath}";
 
             var dbContext = new SqlDbContext();