Bläddra i källkod

Data and Vitorm ReadOnly feature

Lith 10 månader sedan
förälder
incheckning
cf1642484b

+ 1 - 1
src/Vitorm.Data/Data.cs

@@ -80,7 +80,7 @@ namespace Vitorm
             }
             internal bool Match(string classFullName)
             {
-                return classFullName.StartsWith(@namespace);
+                return classFullName.StartsWith(classFullNamePrefix);
             }
         }
 

+ 4 - 9
src/Vitorm.MySql/DataProvider.cs

@@ -5,22 +5,17 @@ using Vitorm.Sql;
 
 namespace Vitorm.MySql
 {
-
     public class DataProvider : SqlDataProvider
     {
         protected Dictionary<string, object> config;
-        protected string connectionString;
-        protected int? commandTimeout;
-        public override SqlDbContext CreateDbContext() => new SqlDbContext().UseMySql(connectionString: connectionString, commandTimeout: commandTimeout);
+        protected DbConfig dbConfig;
+
+        public override SqlDbContext CreateDbContext() => new SqlDbContext().UseMySql(dbConfig);
 
         public override void Init(Dictionary<string, object> config)
         {
             this.config = config;
-            if (config.TryGetValue("connectionString", out var connStr))
-                this.connectionString = connStr as string;
-
-            if (config.TryGetValue("commandTimeout", out var strCommandTimeout) && int.TryParse("" + strCommandTimeout, out var commandTimeout))
-                this.commandTimeout = commandTimeout;
+            this.dbConfig = new(config);
         }
     }
 }

+ 46 - 0
src/Vitorm.MySql/DbConfig.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+
+using DbConnection = MySqlConnector.MySqlConnection;
+
+namespace Vitorm.MySql
+{
+    public class DbConfig
+    {
+        public DbConfig(string connectionString, int? commandTimeout = null)
+        {
+            this.connectionString = connectionString;
+            this.commandTimeout = commandTimeout;
+        }
+        public DbConfig(string connectionString, string readOnlyConnectionString, int? commandTimeout = null)
+        {
+            this.connectionString = connectionString;
+            this.readOnlyConnectionString = readOnlyConnectionString;
+            this.commandTimeout = commandTimeout;
+        }
+        public DbConfig(Dictionary<string, object> config)
+        {
+            object value;
+            if (config.TryGetValue("connectionString", out value))
+                this.connectionString = value as string;
+
+            if (config.TryGetValue("readOnlyConnectionString", out value))
+                this.readOnlyConnectionString = value as string;
+
+            if (config.TryGetValue("commandTimeout", out value) && int.TryParse(value as string, out var commandTimeout))
+                this.commandTimeout = commandTimeout;
+        }
+
+        public string connectionString { get; set; }
+        public string readOnlyConnectionString { get; set; }
+        public int? commandTimeout { get; set; }
+
+        internal string dbHashCode => connectionString.GetHashCode().ToString();
+        internal IDbConnection createDbConnection() => new DbConnection(connectionString);
+        private IDbConnection _createReadOnlyDbConnection() => new DbConnection(readOnlyConnectionString);
+
+        internal Func<IDbConnection> createReadOnlyDbConnection => readOnlyConnectionString == null ? null : _createReadOnlyDbConnection;
+
+    }
+}

+ 15 - 26
src/Vitorm.MySql/DbContext_Extensions_UseMySql.cs

@@ -1,43 +1,32 @@
-using System;
-using System.Data;
-
+using Vitorm.MySql;
 using Vitorm.Sql;
-using Vitorm.Sql.SqlTranslate;
+using Vitorm.Sql.Transaction;
 
 namespace Vitorm
 {
     public static class DbContext_Extensions_UseMySql
     {
-        /*
-         // ref: https://dev.mysql.com/doc/refman/8.4/en/savepoint.html
-         //  https://dev.mysql.com/doc/refman/8.4/en/commit.html
-
-        START TRANSACTION;
-            SET autocommit=0;
-            SAVEPOINT tran0;
-                select '';
-            -- ROLLBACK WORK TO SAVEPOINT tran0;
-            RELEASE SAVEPOINT tran0;
-        COMMIT;
-        -- ROLLBACK;
-         */
         public static SqlDbContext UseMySql(this SqlDbContext dbContext, string connectionString, int? commandTimeout = null)
-        {
-            ISqlTranslateService sqlTranslateService = Vitorm.MySql.SqlTranslateService.Instance;
-
-            Func<IDbConnection> createDbConnection = () => new MySqlConnector.MySqlConnection(connectionString);
+               => UseMySql(dbContext, new DbConfig(connectionString: connectionString, commandTimeout: commandTimeout));
 
+        public static SqlDbContext UseMySql(this SqlDbContext dbContext, DbConfig config)
+        {
+            dbContext.Init(
+                sqlTranslateService: Vitorm.MySql.SqlTranslateService.Instance,
+                createDbConnection: config.createDbConnection,
+                createReadOnlyDbConnection: config.createReadOnlyDbConnection,
+                    dbHashCode: config.dbHashCode
+                );
 
-            dbContext.Init(sqlTranslateService: sqlTranslateService, createDbConnection: createDbConnection, dbHashCode: connectionString.GetHashCode().ToString());
-
-            dbContext.createTransactionScope = (dbContext) => new Vitorm.MySql.SqlTransactionScope(dbContext);
-            //dbContext.createTransactionScope = (dbContext) => new Vitorm.Mysql.SqlTransactionScope_Command(dbContext);
+            dbContext.createTransactionScope = createTransactionScope;
 
-            if (commandTimeout.HasValue) dbContext.commandTimeout = commandTimeout.Value;
+            if (config.commandTimeout.HasValue) dbContext.commandTimeout = config.commandTimeout.Value;
 
             return dbContext;
         }
 
+        static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.MySql.SqlTransactionScope(dbContext);
+        //static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.MySql.SqlTransactionScope_Command(dbContext);
 
 
     }

+ 13 - 0
src/Vitorm.MySql/SqlTransactionScope_Command.cs

@@ -7,6 +7,19 @@ using static Vitorm.Sql.Transaction.DbTransactionWrap;
 
 namespace Vitorm.MySql
 {
+    /*
+           // ref: https://dev.mysql.com/doc/refman/8.4/en/savepoint.html
+           //  https://dev.mysql.com/doc/refman/8.4/en/commit.html
+
+          START TRANSACTION;
+              SET autocommit=0;
+              SAVEPOINT tran0;
+                  select '';
+              -- ROLLBACK WORK TO SAVEPOINT tran0;
+              RELEASE SAVEPOINT tran0;
+          COMMIT;
+          -- ROLLBACK;
+    */
     public class SqlTransactionScope_Command : ITransactionScope
     {
         protected SqlDbContext dbContext;

+ 3 - 9
src/Vitorm.SqlServer/DataProvider.cs

@@ -5,23 +5,17 @@ using Vitorm.Sql;
 
 namespace Vitorm.SqlServer
 {
-
     public class DataProvider : SqlDataProvider
     {
         protected Dictionary<string, object> config;
-        protected string connectionString;
-        protected int? commandTimeout;
+        protected DbConfig dbConfig;
 
-        public override SqlDbContext CreateDbContext() => new SqlDbContext().UseSqlServer(connectionString: connectionString, commandTimeout: commandTimeout);
+        public override SqlDbContext CreateDbContext() => new SqlDbContext().UseSqlServer(dbConfig);
 
         public override void Init(Dictionary<string, object> config)
         {
             this.config = config;
-            if (config.TryGetValue("connectionString", out var connStr))
-                this.connectionString = connStr as string;
-
-            if (config.TryGetValue("commandTimeout", out var strCommandTimeout) && int.TryParse("" + strCommandTimeout, out var commandTimeout))
-                this.commandTimeout = commandTimeout;
+            this.dbConfig = new(config);
         }
     }
 }

+ 46 - 0
src/Vitorm.SqlServer/DbConfig.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+
+using DbConnection = Microsoft.Data.SqlClient.SqlConnection;
+
+namespace Vitorm.SqlServer
+{
+    public class DbConfig
+    {
+        public DbConfig(string connectionString, int? commandTimeout = null)
+        {
+            this.connectionString = connectionString;
+            this.commandTimeout = commandTimeout;
+        }
+        public DbConfig(string connectionString, string readOnlyConnectionString, int? commandTimeout = null)
+        {
+            this.connectionString = connectionString;
+            this.readOnlyConnectionString = readOnlyConnectionString;
+            this.commandTimeout = commandTimeout;
+        }
+        public DbConfig(Dictionary<string, object> config)
+        {
+            object value;
+            if (config.TryGetValue("connectionString", out value))
+                this.connectionString = value as string;
+
+            if (config.TryGetValue("readOnlyConnectionString", out value))
+                this.readOnlyConnectionString = value as string;
+
+            if (config.TryGetValue("commandTimeout", out value) && int.TryParse(value as string, out var commandTimeout))
+                this.commandTimeout = commandTimeout;
+        }
+
+        public string connectionString { get; set; }
+        public string readOnlyConnectionString { get; set; }
+        public int? commandTimeout { get; set; }
+
+        internal string dbHashCode => connectionString.GetHashCode().ToString();
+        internal IDbConnection createDbConnection() => new DbConnection(connectionString);
+        private IDbConnection _createReadOnlyDbConnection() => new DbConnection(readOnlyConnectionString);
+
+        internal Func<IDbConnection> createReadOnlyDbConnection => readOnlyConnectionString == null ? null : _createReadOnlyDbConnection;
+
+    }
+}

+ 15 - 13
src/Vitorm.SqlServer/DbContext_Extensions_UseSqlServer.cs

@@ -1,29 +1,31 @@
-using System;
-using System.Data;
-
-using Vitorm.Sql;
-using Vitorm.Sql.SqlTranslate;
+using Vitorm.Sql;
+using Vitorm.Sql.Transaction;
+using Vitorm.SqlServer;
 
 namespace Vitorm
 {
     public static class DbContext_Extensions_UseSqlServer
     {
         public static SqlDbContext UseSqlServer(this SqlDbContext dbContext, string connectionString, int? commandTimeout = null)
-        {
-            ISqlTranslateService sqlTranslateService = Vitorm.SqlServer.SqlTranslateService.Instance;
-
-            Func<IDbConnection> createDbConnection = () => new Microsoft.Data.SqlClient.SqlConnection(connectionString);
+             => UseSqlServer(dbContext, new DbConfig(connectionString: connectionString, commandTimeout: commandTimeout));
 
-            dbContext.Init(sqlTranslateService: sqlTranslateService, createDbConnection: createDbConnection, dbHashCode: connectionString.GetHashCode().ToString());
+        public static SqlDbContext UseSqlServer(this SqlDbContext dbContext, DbConfig config)
+        {
+            dbContext.Init(
+                sqlTranslateService: Vitorm.SqlServer.SqlTranslateService.Instance,
+                createDbConnection: config.createDbConnection,
+                createReadOnlyDbConnection: config.createReadOnlyDbConnection,
+                dbHashCode: config.dbHashCode
+                );
 
-            dbContext.createTransactionScope = (dbContext) => new Vitorm.SqlServer.SqlTransactionScope(dbContext);
+            dbContext.createTransactionScope = createTransactionScope;
 
-            if (commandTimeout.HasValue) dbContext.commandTimeout = commandTimeout.Value;
+            if (config.commandTimeout.HasValue) dbContext.commandTimeout = config.commandTimeout.Value;
 
             return dbContext;
         }
 
-
+        static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.SqlServer.SqlTransactionScope(dbContext);
 
     }
 }

+ 3 - 9
src/Vitorm.Sqlite/DataProvider.cs

@@ -5,23 +5,17 @@ using Vitorm.Sql;
 
 namespace Vitorm.Sqlite
 {
-
     public class DataProvider : SqlDataProvider
     {
         protected Dictionary<string, object> config;
-        protected string connectionString;
-        protected int? commandTimeout;
+        protected DbConfig dbConfig;
 
-        public override SqlDbContext CreateDbContext() => new SqlDbContext().UseSqlite(connectionString: connectionString, commandTimeout: commandTimeout);
+        public override SqlDbContext CreateDbContext() => new SqlDbContext().UseSqlite(dbConfig);
 
         public override void Init(Dictionary<string, object> config)
         {
             this.config = config;
-            if (config.TryGetValue("connectionString", out var connStr))
-                this.connectionString = connStr as string;
-
-            if (config.TryGetValue("commandTimeout", out var strCommandTimeout) && int.TryParse("" + strCommandTimeout, out var commandTimeout))
-                this.commandTimeout = commandTimeout;
+            this.dbConfig = new(config);
         }
     }
 }

+ 46 - 0
src/Vitorm.Sqlite/DbConfig.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+
+using DbConnection = Microsoft.Data.Sqlite.SqliteConnection;
+
+namespace Vitorm.Sqlite
+{
+    public class DbConfig
+    {
+        public DbConfig(string connectionString, int? commandTimeout = null)
+        {
+            this.connectionString = connectionString;
+            this.commandTimeout = commandTimeout;
+        }
+        public DbConfig(string connectionString, string readOnlyConnectionString, int? commandTimeout = null)
+        {
+            this.connectionString = connectionString;
+            this.readOnlyConnectionString = readOnlyConnectionString;
+            this.commandTimeout = commandTimeout;
+        }
+        public DbConfig(Dictionary<string, object> config)
+        {
+            object value;
+            if (config.TryGetValue("connectionString", out value))
+                this.connectionString = value as string;
+
+            if (config.TryGetValue("readOnlyConnectionString", out value))
+                this.readOnlyConnectionString = value as string;
+
+            if (config.TryGetValue("commandTimeout", out value) && int.TryParse(value as string, out var commandTimeout))
+                this.commandTimeout = commandTimeout;
+        }
+
+        public string connectionString { get; set; }
+        public string readOnlyConnectionString { get; set; }
+        public int? commandTimeout { get; set; }
+
+        internal string dbHashCode => connectionString.GetHashCode().ToString();
+        internal IDbConnection createDbConnection() => new DbConnection(connectionString);
+        private IDbConnection _createReadOnlyDbConnection() => new DbConnection(readOnlyConnectionString);
+
+        internal Func<IDbConnection> createReadOnlyDbConnection => readOnlyConnectionString == null ? null : _createReadOnlyDbConnection;
+
+    }
+}

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

@@ -1,30 +1,30 @@
-using System;
-using System.Data;
-
-using Vitorm.Sql;
-using Vitorm.Sql.SqlTranslate;
+using Vitorm.Sql;
+using Vitorm.Sql.Transaction;
+using Vitorm.Sqlite;
 
 namespace Vitorm
 {
     public static class DbContext_Extensions_UseSqlite
     {
         public static SqlDbContext UseSqlite(this SqlDbContext dbContext, string connectionString, int? commandTimeout = null)
-        {
-            ISqlTranslateService sqlTranslateService = Vitorm.Sqlite.SqlTranslateService.Instance;
-
-            Func<IDbConnection> createDbConnection = () => new Microsoft.Data.Sqlite.SqliteConnection(connectionString);
-
+            => UseSqlite(dbContext, new DbConfig(connectionString: connectionString, commandTimeout: commandTimeout));
 
-            dbContext.Init(sqlTranslateService: sqlTranslateService, createDbConnection: createDbConnection, dbHashCode: connectionString.GetHashCode().ToString());
+        public static SqlDbContext UseSqlite(this SqlDbContext dbContext, DbConfig config)
+        {
+            dbContext.Init(
+                sqlTranslateService: Vitorm.Sqlite.SqlTranslateService.Instance,
+                createDbConnection: config.createDbConnection,
+                createReadOnlyDbConnection: config.createReadOnlyDbConnection,
+                dbHashCode: config.dbHashCode
+                );
 
-            dbContext.createTransactionScope = (dbContext) => new Vitorm.Sqlite.SqlTransactionScope(dbContext);
+            dbContext.createTransactionScope = createTransactionScope;
 
-            if (commandTimeout.HasValue) dbContext.commandTimeout = commandTimeout.Value;
+            if (config.commandTimeout.HasValue) dbContext.commandTimeout = config.commandTimeout.Value;
 
             return dbContext;
         }
 
-
-
+        static ITransactionScope createTransactionScope(SqlDbContext dbContext) => new Vitorm.Sqlite.SqlTransactionScope(dbContext);
     }
 }

+ 68 - 20
src/Vitorm/Sql/SqlDbContext.cs

@@ -16,29 +16,50 @@ namespace Vitorm.Sql
     public partial class SqlDbContext : DbContext
     {
         protected Func<IDbConnection> createDbConnection { get; set; }
+        protected Func<IDbConnection> createReadOnlyDbConnection { get; set; }
         protected IDbConnection _dbConnection;
+        protected IDbConnection _readOnlyDbConnection;
         public override void Dispose()
         {
             try
             {
-                base.Dispose();
+                transactionScope?.Dispose();
             }
             finally
             {
+                transactionScope = null;
                 try
                 {
-                    transactionScope?.Dispose();
+                    _dbConnection?.Dispose();
                 }
                 finally
                 {
-                    transactionScope = null;
-
-                    _dbConnection?.Dispose();
                     _dbConnection = null;
+
+                    try
+                    {
+                        _readOnlyDbConnection?.Dispose();
+                    }
+                    finally
+                    {
+                        _readOnlyDbConnection = null;
+
+                        base.Dispose();
+                    }
                 }
             }
         }
         public virtual IDbConnection dbConnection => _dbConnection ??= createDbConnection();
+        public virtual IDbConnection readOnlyDbConnection
+        {
+            get
+            {
+                if (_readOnlyDbConnection != null) return _readOnlyDbConnection;
+                if (createReadOnlyDbConnection != null) return _readOnlyDbConnection = createReadOnlyDbConnection();
+
+                return dbConnection;
+            }
+        }
 
 
         public virtual ISqlTranslateService sqlTranslateService { get; private set; }
@@ -51,12 +72,14 @@ namespace Vitorm.Sql
         /// </summary>
         /// <param name="sqlTranslateService"></param>
         /// <param name="createDbConnection"></param>
+        /// <param name="createReadOnlyDbConnection"></param>
         /// <param name="sqlExecutor"></param>
         /// <param name="dbHashCode"> to identify whether contexts are from the same database </param>
-        public virtual void Init(ISqlTranslateService sqlTranslateService, Func<IDbConnection> createDbConnection, SqlExecutor sqlExecutor = null, string dbHashCode = null)
+        public virtual void Init(ISqlTranslateService sqlTranslateService, Func<IDbConnection> createDbConnection, Func<IDbConnection> createReadOnlyDbConnection = null, SqlExecutor sqlExecutor = null, string dbHashCode = null)
         {
             this.sqlTranslateService = sqlTranslateService;
             this.createDbConnection = createDbConnection;
+            this.createReadOnlyDbConnection = createReadOnlyDbConnection;
             this.sqlExecutor = sqlExecutor ?? SqlExecutor.Instance;
 
             if (string.IsNullOrEmpty(dbHashCode))
@@ -217,7 +240,7 @@ namespace Vitorm.Sql
             sqlParam[entityDescriptor.keyName] = keyValue;
 
             // #3 execute
-            using var reader = ExecuteReader(sql: sql, param: sqlParam);
+            using var reader = ExecuteReader(sql: sql, param: sqlParam, useReadOnly: true);
             if (reader.Read())
             {
                 var entity = (Entity)Activator.CreateInstance(typeof(Entity));
@@ -261,7 +284,7 @@ namespace Vitorm.Sql
             return this;
         }
 
-        protected object ExecuteQuery(Expression expression, Type type)
+        protected virtual object ExecuteQuery(Expression expression, Type type)
         {
             // #1 convert to ExpressionNode 
             ExpressionNode node = convertService.ConvertToData(expression, autoReduce: true, isArgument: QueryIsFromSameDb);
@@ -313,7 +336,7 @@ namespace Vitorm.Sql
 
                         (string sql, Dictionary<string, object> sqlParam, IDbDataReader dataReader) = sqlTranslateService.PrepareQuery(arg, combinedStream);
 
-                        var count = ExecuteScalar(sql: sql, param: sqlParam);
+                        var count = ExecuteScalar(sql: sql, param: sqlParam, useReadOnly: true);
                         return Convert.ToInt32(count);
                     }
                 case nameof(Orm_Extensions.ExecuteDelete):
@@ -337,7 +360,7 @@ namespace Vitorm.Sql
 
                         (string sql, Dictionary<string, object> sqlParam, IDbDataReader dataReader) = sqlTranslateService.PrepareQuery(arg, combinedStream);
 
-                        using var reader = ExecuteReader(sql: sql, param: sqlParam);
+                        using var reader = ExecuteReader(sql: sql, param: sqlParam, useReadOnly: true);
                         return dataReader.ReadData(reader);
                     }
                 case "ToList":
@@ -352,7 +375,7 @@ namespace Vitorm.Sql
 
                         (string sql, Dictionary<string, object> sqlParam, IDbDataReader dataReader) = sqlTranslateService.PrepareQuery(arg, combinedStream);
 
-                        using var reader = ExecuteReader(sql: sql, param: sqlParam);
+                        using var reader = ExecuteReader(sql: sql, param: sqlParam, useReadOnly: true);
                         return dataReader.ReadData(reader);
                     }
             }
@@ -492,28 +515,53 @@ namespace Vitorm.Sql
         public virtual int ExecuteWithTransaction(string sql, IDictionary<string, object> param = null, IDbTransaction transaction = null)
         {
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
+
             return sqlExecutor.Execute(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
         }
 
-        public virtual int Execute(string sql, IDictionary<string, object> param = null, int? commandTimeout = null)
+        public virtual int Execute(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
         {
-            var transaction = GetCurrentTransaction();
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            return sqlExecutor.Execute(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
+            var transaction = GetCurrentTransaction();
+
+            if (useReadOnly && transaction == null)
+            {
+                return sqlExecutor.Execute(readOnlyDbConnection, sql, param: param, commandTimeout: commandTimeout);
+            }
+            else
+            {
+                return sqlExecutor.Execute(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
+            }
         }
 
-        public virtual IDataReader ExecuteReader(string sql, IDictionary<string, object> param = null, int? commandTimeout = null)
+        public virtual IDataReader ExecuteReader(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
         {
-            var transaction = GetCurrentTransaction();
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            return sqlExecutor.ExecuteReader(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
+            var transaction = GetCurrentTransaction();
+
+            if (useReadOnly && transaction == null)
+            {
+                return sqlExecutor.ExecuteReader(readOnlyDbConnection, sql, param: param, commandTimeout: commandTimeout);
+            }
+            else
+            {
+                return sqlExecutor.ExecuteReader(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
+            }
         }
 
-        public virtual object ExecuteScalar(string sql, IDictionary<string, object> param = null, int? commandTimeout = null)
+        public virtual object ExecuteScalar(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
         {
-            var transaction = GetCurrentTransaction();
             commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
-            return sqlExecutor.ExecuteScalar(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
+            var transaction = GetCurrentTransaction();
+
+            if (useReadOnly && transaction == null)
+            {
+                return sqlExecutor.ExecuteScalar(readOnlyDbConnection, sql, param: param, commandTimeout: commandTimeout);
+            }
+            else
+            {
+                return sqlExecutor.ExecuteScalar(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
+            }
         }
         #endregion
 

+ 81 - 0
test/Vitorm.Data.MsTest/CommonTest/SqliteReadOnly_Test.cs

@@ -0,0 +1,81 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Vitorm.Sql;
+
+using User = Vitorm.MsTest.Sqlite2.User;
+
+namespace Vitorm.MsTest.Sqlite2
+{
+    public class User : Vitorm.MsTest.UserBase
+    {
+    }
+}
+
+
+namespace Vitorm.MsTest
+{
+
+    [TestClass]
+    public partial class SqliteReadOnly_Test
+    {
+
+        [TestMethod]
+        public void Test()
+        {
+            Init("SqliteReadOnly_Test.db");
+            Init("SqliteReadOnly_Test.readonly.db");
+
+            // #1 get from ReadOnly node
+            {
+                var user = Data.Get<User>(1);
+                Assert.AreEqual("SqliteReadOnly_Test.readonly.db", user.name);
+            }
+
+            // #2 get from ReadWrite node by transaction
+            {
+                using var dbContext = Data.DataProvider<User>().CreateSqlDbContext();
+                using var tran = dbContext.BeginTransaction();
+
+                var user = dbContext.Get<User>(1);
+                Assert.AreEqual("SqliteReadOnly_Test.db", user.name);
+            }
+
+            // #3 update and check
+            {
+                // get from ReadOnly node
+                var user = Data.Get<User>(1);
+                Assert.AreEqual("SqliteReadOnly_Test.readonly.db", user.name);
+
+                // update to ReadWrite node
+                user.name = "NewName";
+                Data.Update(user);
+
+                // get from ReadOnly node
+                user = Data.Get<User>(1);
+                Assert.AreEqual("SqliteReadOnly_Test.readonly.db", user.name);
+
+                // get from ReadWrite node
+                using var dbContext = Data.DataProvider<User>().CreateSqlDbContext();
+                using var tran = dbContext.BeginTransaction();
+                user = dbContext.Get<User>(1);
+                Assert.AreEqual("NewName", user.name);
+            }
+        }
+
+
+        public void Init(string fileName)
+        {
+            var filePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, fileName);
+            if (File.Exists(filePath)) File.Delete(filePath);
+            File.WriteAllBytes(filePath, new byte[0]);
+
+            using var dbContext = new SqlDbContext().UseSqlite(connectionString: $"data source={fileName};");
+
+            dbContext.Drop<User>();
+            dbContext.Create<User>();
+            dbContext.Add(new User { id = 1, name = fileName });
+        }
+
+
+    }
+}

+ 7 - 7
test/Vitorm.Data.MsTest/Vitorm.Data.MsTest.csproj

@@ -18,15 +18,15 @@
     </ItemGroup>
 
     <ItemGroup>
-      <ProjectReference Include="..\..\..\Vitorm.ClickHouse\src\Vitorm.ClickHouse\Vitorm.ClickHouse.csproj" />
-      <ProjectReference Include="..\..\..\Vitorm.ElasticSearch\src\Vitorm.ElasticSearch\Vitorm.ElasticSearch.csproj" />
-      <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.MySql\Vitorm.MySql.csproj" />
-      <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.Sqlite\Vitorm.Sqlite.csproj" />
-      <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.SqlServer\Vitorm.SqlServer.csproj" />
-      <ProjectReference Include="..\..\src\Vitorm.Data\Vitorm.Data.csproj" />
+        <ProjectReference Include="..\..\..\Vitorm.ClickHouse\src\Vitorm.ClickHouse\Vitorm.ClickHouse.csproj" />
+        <ProjectReference Include="..\..\..\Vitorm.ElasticSearch\src\Vitorm.ElasticSearch\Vitorm.ElasticSearch.csproj" />
+        <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.MySql\Vitorm.MySql.csproj" />
+        <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.Sqlite\Vitorm.Sqlite.csproj" />
+        <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.SqlServer\Vitorm.SqlServer.csproj" />
+        <ProjectReference Include="..\..\src\Vitorm.Data\Vitorm.Data.csproj" />
     </ItemGroup>
 
- 
+
     <ItemGroup>
         <None Update="appsettings.json">
             <CopyToOutputDirectory>Always</CopyToOutputDirectory>

+ 52 - 0
test/Vitorm.Data.MsTest/appsettings.json

@@ -0,0 +1,52 @@
+{
+  "Vitorm": {
+    "Data": [
+      {
+        "provider": "Sqlite",
+
+        "namespace": "Vitorm.MsTest.Sqlite",
+        "//commandTimeout": 60,
+        "connectionString": "data source=sqlite.db;"
+      },
+      {
+        "provider": "Vitorm.MySql.DataProvider",
+        "assemblyFile": "Vitorm.MySql.dll",
+
+        "namespace": "Vitorm.MsTest.MySql",
+        "//commandTimeout": 60,
+        "connectionString": "Data Source=ki.lith.cloud;Port=3306;Database=dev-orm;SslMode=none;User Id=root;Password=mysqlasgd234548222sdf5;CharSet=utf8;allowPublicKeyRetrieval=true;"
+      },
+      {
+        "provider": "Vitorm.SqlServer.DataProvider",
+        "assemblyName": "Vitorm.SqlServer",
+
+        "namespace": "Vitorm.MsTest.SqlServer",
+        "//commandTimeout": 60,
+        "connectionString": "Server=ki.lith.cloud;Database=dev-orm;User ID=sa;Password=Admin0123;TrustServerCertificate=true;"
+      },
+      {
+        "provider": "ClickHouse",
+
+        "namespace": "Vitorm.MsTest.ClickHouse",
+        "//commandTimeout": 60,
+        "connectionString": "Host=192.168.20.20;Port=8123;Database=dev-orm;User=default;Password=;Compress=True;CheckCompressedHash=False;Compressor=lz4;"
+      },
+      {
+        "provider": "ElasticSearch",
+
+        "namespace": "Vitorm.MsTest.ElasticSearch",
+        "//commandTimeout": 60,
+        "connectionString": "http://ki.lith.cloud:9200"
+      },
+
+
+      {
+        "provider": "Sqlite",
+        "namespace": "Vitorm.MsTest.Sqlite2",
+        "connectionString": "data source=SqliteReadOnly_Test.db;",
+        "readOnlyConnectionString": "data source=SqliteReadOnly_Test.readonly.db;"
+      }
+
+    ]
+  }
+}