Forráskód Böngészése

[Release] Vitorm release/2.0.2

Lith 9 hónapja
szülő
commit
7e503c62d0
45 módosított fájl, 1422 hozzáadás és 347 törlés
  1. 14 0
      Vitorm.sln
  2. 1 0
      doc/ReleaseLog.md
  3. 3 3
      src/Vitorm.Data/Data.cs
  4. 1 1
      src/Vitorm.Data/Vitorm.Data.csproj
  5. 16 0
      src/Vitorm.EntityGenerate/DataEntity.cs
  6. 217 0
      src/Vitorm.EntityGenerate/EntityGenerate/EntityGenerator.cs
  7. 69 0
      src/Vitorm.EntityGenerate/EntityGenerate/EntityHelp.cs
  8. 167 0
      src/Vitorm.EntityGenerate/Extensions/IDbSet_Extensions.cs
  9. 39 0
      src/Vitorm.EntityGenerate/Extensions/IDbSet_Extensions_Origin.cs
  10. 41 0
      src/Vitorm.EntityGenerate/Extensions/SqlDbContext_EntityType_Extensions.cs
  11. 72 0
      src/Vitorm.EntityGenerate/README.md
  12. 44 0
      src/Vitorm.EntityGenerate/Vitorm.EntityGenerate.csproj
  13. 1 1
      src/Vitorm.MySql/Vitorm.MySql.csproj
  14. 1 1
      src/Vitorm.SqlServer/SqlTranslateService.cs
  15. 1 1
      src/Vitorm.SqlServer/Vitorm.SqlServer.csproj
  16. 2 2
      src/Vitorm.Sqlite/Vitorm.Sqlite.csproj
  17. 31 27
      src/Vitorm/DbContext.cs
  18. 11 13
      src/Vitorm/DbSet.cs
  19. 4 4
      src/Vitorm/Entity/DataAnnotations/EntityLoader.cs
  20. 9 2
      src/Vitorm/Entity/Loader/DefaultEntityLoader.cs
  21. 1 0
      src/Vitorm/Entity/Loader/IEntityLoader.cs
  22. 3 1
      src/Vitorm/Entity/LoaderAttribute/EntityLoaderFromAttribute.cs
  23. 36 1
      src/Vitorm/IDbSet.cs
  24. 1 1
      src/Vitorm/Sql/DbConnectionProvider.cs
  25. 47 261
      src/Vitorm/Sql/SqlDbContext.cs
  26. 274 0
      src/Vitorm/Sql/SqlDbSet.cs
  27. 2 3
      src/Vitorm/Vitorm.csproj
  28. 1 1
      test/Vitorm.Data.Benchmark/Vitorm.Data.Benchmark.csproj
  29. 1 3
      test/Vitorm.Data.MsTest/CommonTest/ClickHouse_Test.cs
  30. 1 3
      test/Vitorm.Data.MsTest/CommonTest/MySql_Test.cs
  31. 1 3
      test/Vitorm.Data.MsTest/CommonTest/SqlServer_Test.cs
  32. 4 4
      test/Vitorm.Data.MsTest/Vitorm.Data.MsTest.csproj
  33. 78 0
      test/Vitorm.EntityGenerate.MsTest/BaseTest.cs
  34. 41 0
      test/Vitorm.EntityGenerate.MsTest/SqlServer/EntityGenerate_Data_Test.cs
  35. 44 0
      test/Vitorm.EntityGenerate.MsTest/SqlServer/EntityGenerate_Test.cs
  36. 43 0
      test/Vitorm.EntityGenerate.MsTest/Sqlite_Test/EntityGenerate_Data_Test.cs
  37. 39 0
      test/Vitorm.EntityGenerate.MsTest/Sqlite_Test/EntityGenerate_Test.cs
  38. 33 0
      test/Vitorm.EntityGenerate.MsTest/Vitorm.EntityGenerate.MsTest.csproj
  39. 17 0
      test/Vitorm.EntityGenerate.MsTest/appsettings.json
  40. 3 2
      test/Vitorm.MySql.MsTest/Vitorm.MySql.MsTest.csproj
  41. 3 2
      test/Vitorm.SqlServer.MsTest/Vitorm.SqlServer.MsTest.csproj
  42. 1 0
      test/Vitorm.Sqlite.MsTest/CommonTest/DbContext_Test.cs
  43. 1 4
      test/Vitorm.Sqlite.MsTest/ExpressionTreeTest/ExpressionTester.cs
  44. 1 1
      test/Vitorm.Sqlite.MsTest/ExpressionTreeTest/Query_Test.cs
  45. 2 2
      test/Vitorm.Sqlite.MsTest/Vitorm.Sqlite.MsTest.csproj

+ 14 - 0
Vitorm.sln

@@ -39,6 +39,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vitorm.Sqlite.Console", "te
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vitorm.Data.Benchmark", "test\Vitorm.Data.Benchmark\Vitorm.Data.Benchmark.csproj", "{02AE1368-8B79-4CE2-8518-13A7B91D345B}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vitorm.EntityGenerate", "src\Vitorm.EntityGenerate\Vitorm.EntityGenerate.csproj", "{5A189C1D-E909-4164-BFF1-67BDE2C37D08}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vitorm.EntityGenerate.MsTest", "test\Vitorm.EntityGenerate.MsTest\Vitorm.EntityGenerate.MsTest.csproj", "{BAC8E2E5-23DE-4BCF-829F-E6B04C86FEEF}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -93,6 +97,14 @@ Global
 		{02AE1368-8B79-4CE2-8518-13A7B91D345B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{02AE1368-8B79-4CE2-8518-13A7B91D345B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{02AE1368-8B79-4CE2-8518-13A7B91D345B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5A189C1D-E909-4164-BFF1-67BDE2C37D08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5A189C1D-E909-4164-BFF1-67BDE2C37D08}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5A189C1D-E909-4164-BFF1-67BDE2C37D08}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5A189C1D-E909-4164-BFF1-67BDE2C37D08}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BAC8E2E5-23DE-4BCF-829F-E6B04C86FEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BAC8E2E5-23DE-4BCF-829F-E6B04C86FEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BAC8E2E5-23DE-4BCF-829F-E6B04C86FEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BAC8E2E5-23DE-4BCF-829F-E6B04C86FEEF}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -110,6 +122,8 @@ Global
 		{DACD0587-AF7F-4ACC-9E67-1E8196C66DAF} = {7904FE51-04FF-4477-8E3A-CC340389EE32}
 		{FDE612FB-A590-4937-93E8-314C9DF9F39E} = {7904FE51-04FF-4477-8E3A-CC340389EE32}
 		{02AE1368-8B79-4CE2-8518-13A7B91D345B} = {7904FE51-04FF-4477-8E3A-CC340389EE32}
+		{5A189C1D-E909-4164-BFF1-67BDE2C37D08} = {05176905-A2A5-4015-9F04-2904506C902F}
+		{BAC8E2E5-23DE-4BCF-829F-E6B04C86FEEF} = {7904FE51-04FF-4477-8E3A-CC340389EE32}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {C7DA16E3-9949-49FA-B0B4-F830636DE60F}

+ 1 - 0
doc/ReleaseLog.md

@@ -3,6 +3,7 @@
 # 2.0.1
 
 - support ToListAsync
+- Extensions for IDbSet
 
 
 -----------------------

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

@@ -17,14 +17,14 @@ namespace Vitorm
         static Data()
         {
             var dataSourceConfigs = Appsettings.json.GetByPath<List<Dictionary<string, object>>>("Vitorm.Data");
-            var dataProviders = dataSourceConfigs?.Select(GetDataProvider).NotNull().ToList();
+            var dataProviders = dataSourceConfigs?.Select(CreateDataProvider).NotNull().ToList();
 
             if (dataProviders?.Any() == true) providerCache.AddRange(dataProviders);
         }
 
         public static bool AddDataSource(Dictionary<string, object> dataSourceConfig)
         {
-            var provider = GetDataProvider(dataSourceConfig);
+            var provider = CreateDataProvider(dataSourceConfig);
             if (provider == null) return false;
 
             providerCache.Insert(0, provider);
@@ -66,7 +66,7 @@ namespace Vitorm
         static readonly List<DataProviderCache> providerCache = new();
 
 
-        static DataProviderCache GetDataProvider(Dictionary<string, object> dataSourceConfig)
+        static DataProviderCache CreateDataProvider(Dictionary<string, object> dataSourceConfig)
         {
             /*
             "provider": "Vitorm.Sqlite.DataProvider",

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

@@ -6,7 +6,7 @@
 
     <PropertyGroup>
         <TargetFramework>netstandard2.0</TargetFramework>
-        <Version>2.0.1</Version>
+        <Version>2.0.2</Version>
         <LangVersion>9.0</LangVersion>
     </PropertyGroup>
 

+ 16 - 0
src/Vitorm.EntityGenerate/DataEntity.cs

@@ -0,0 +1,16 @@
+using Vitorm.Sql;
+
+
+namespace Vitorm.EntityGenerate
+{
+    public static partial class DataEntity
+    {
+        public static IDbSet GenerateDbSet(string entityNamespace, string tableName, string schemaName = null, bool cacheEntity = false)
+        {
+            var dataProvider = Data.DataProvider(entityNamespace);
+            SqlDbContext dbContext = dataProvider?.CreateSqlDbContext();
+            return dbContext?.GenerateDbSet(entityNamespace, tableName, schemaName, cacheEntity);
+        }
+
+    }
+}

+ 217 - 0
src/Vitorm.EntityGenerate/EntityGenerate/EntityGenerator.cs

@@ -0,0 +1,217 @@
+#region << Version-v3 >>
+/*
+ * ========================================================================
+ * Version: v3
+ * Time   : 2024-07-28
+ * Author : lith
+ * Email  : LithWang@outlook.com
+ * Remarks: 
+ * ========================================================================
+*/
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Vit.DynamicCompile.EntityGenerate
+{
+    /*
+// https://www.cnblogs.com/sesametech-dotnet/p/13176329.html
+// https://learn.microsoft.com/zh-cn/dotnet/api/system.reflection.emit.constructorbuilder?view=net-8.0
+
+<ItemGroup>
+    <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
+    <PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
+</ItemGroup>
+     */
+
+    internal class EntityGenerator
+    {
+        public static CustomAttributeBuilder GetAttributeBuilder<CustomAttribute>(
+            IEnumerable<(Type type, object value)> constructorArgs = null
+            , IEnumerable<(string name, object value)> propertyValues = null
+            )
+            where CustomAttribute : Attribute
+        {
+            constructorArgs ??= new List<(Type type, object value)>();
+            propertyValues ??= new List<(string name, object value)>();
+
+            var type = typeof(CustomAttribute);
+            var ci = type.GetConstructor(constructorArgs.Select(m => m.type).ToArray());
+            var builder = new CustomAttributeBuilder(
+                ci
+                , constructorArgs.Select(m => m.value).ToArray()
+                , propertyValues.Select(property => type.GetProperty(property.name)).ToArray()
+                , propertyValues.Select(m => m.value).ToArray()
+                );
+            return builder;
+        }
+
+        public static CustomAttributeBuilder GetAttributeBuilder<CustomAttribute>
+            (IEnumerable<object> constructorArgs, IEnumerable<(string name, object value)> propertyValues = null)
+            where CustomAttribute : Attribute
+            => GetAttributeBuilder<CustomAttribute>(constructorArgs.Select(value => (value.GetType(), value)), propertyValues);
+
+
+        public static Type CreateType(TypeDescriptor typeDescriptor)
+        {
+            // #1 define Type
+            var assemblyName = new AssemblyName(typeDescriptor.assemblyName);
+            var dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+            var dynamicModule = dynamicAssembly.DefineDynamicModule(typeDescriptor.moduleName);
+            var typeBuilder = dynamicModule.DefineType(typeDescriptor.typeName,
+                    TypeAttributes.Public |
+                    TypeAttributes.Class |
+                    TypeAttributes.AutoClass |
+                    TypeAttributes.AnsiClass |
+                    TypeAttributes.BeforeFieldInit |
+                    TypeAttributes.AutoLayout,
+                    null);     // This is the type of class to derive from. Use null if there isn't one
+
+            typeBuilder.DefineDefaultConstructor(MethodAttributes.Public |
+                                                MethodAttributes.SpecialName |
+                                                MethodAttributes.RTSpecialName);
+
+            // #2 Add Property
+            typeDescriptor.properties?.ForEach(property => AddProperty(typeBuilder, property));
+
+
+            // #3 attributes
+            typeDescriptor.attributes?.ForEach(attribute => typeBuilder.SetCustomAttribute(attribute));
+
+            var generatedType = typeBuilder.CreateTypeInfo().AsType();
+            return generatedType;
+        }
+        private static void AddProperty(TypeBuilder typeBuilder, PropertyDescriptor propertyDescriptor)
+        {
+            var propertyName = propertyDescriptor.name;
+            var propertyType = propertyDescriptor.type;
+
+            // #1 field
+            var fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
+            var propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
+
+            // #2 get
+            {
+                var getMethod = typeBuilder.DefineMethod("get_" + propertyName,
+                    MethodAttributes.Public |
+                    MethodAttributes.SpecialName |
+                    MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
+                var getMethodIL = getMethod.GetILGenerator();
+                getMethodIL.Emit(OpCodes.Ldarg_0);
+                getMethodIL.Emit(OpCodes.Ldfld, fieldBuilder);
+                getMethodIL.Emit(OpCodes.Ret);
+
+                propertyBuilder.SetGetMethod(getMethod);
+            }
+
+            // #3 set
+            {
+                var setMethod = typeBuilder.DefineMethod("set_" + propertyName,
+                      MethodAttributes.Public |
+                      MethodAttributes.SpecialName |
+                      MethodAttributes.HideBySig,
+                      null, new[] { propertyType });
+                var setMethodIL = setMethod.GetILGenerator();
+                Label modifyProperty = setMethodIL.DefineLabel();
+                Label exitSet = setMethodIL.DefineLabel();
+
+                setMethodIL.MarkLabel(modifyProperty);
+                setMethodIL.Emit(OpCodes.Ldarg_0);
+                setMethodIL.Emit(OpCodes.Ldarg_1);
+                setMethodIL.Emit(OpCodes.Stfld, fieldBuilder);
+                setMethodIL.Emit(OpCodes.Nop);
+                setMethodIL.MarkLabel(exitSet);
+                setMethodIL.Emit(OpCodes.Ret);
+
+                propertyBuilder.SetSetMethod(setMethod);
+            }
+
+            // #4 attributes
+            propertyDescriptor.attributes?.ForEach(attribute => propertyBuilder.SetCustomAttribute(attribute));
+        }
+    }
+
+
+
+
+    #region TypeDescriptor
+    public class TypeDescriptor
+    {
+        public string assemblyName;
+        public string moduleName;
+        /// <summary>
+        /// The full path of the type. name cannot contain embedded nulls.
+        /// </summary>
+        public string typeName;
+
+        public List<CustomAttributeBuilder> attributes;
+
+        public List<PropertyDescriptor> properties;
+
+        public TypeDescriptor() { }
+
+        public TypeDescriptor(Dictionary<string, Type> propertiesMap)
+        {
+            assemblyName = Guid.NewGuid().ToString();
+            moduleName = "Main";
+            typeName = "DynamicClass";
+            properties = propertiesMap.AsEnumerable().Select(kv => new PropertyDescriptor { name = kv.Key, type = kv.Value }).ToList();
+        }
+
+        public TypeDescriptor AddAttribute<CustomAttribute>(
+           IEnumerable<(Type type, object value)> constructorArgs = null
+           , IEnumerable<(string name, object value)> propertyValues = null
+           )
+           where CustomAttribute : Attribute
+        {
+            attributes ??= new();
+            attributes.Add(EntityGenerator.GetAttributeBuilder<CustomAttribute>(constructorArgs, propertyValues));
+            return this;
+        }
+        public TypeDescriptor AddAttribute<CustomAttribute>(IEnumerable<object> constructorArgs, IEnumerable<(string name, object value)> propertyValues = null)
+           where CustomAttribute : Attribute
+           => AddAttribute<CustomAttribute>(constructorArgs.Select(value => (value.GetType(), value)), propertyValues);
+
+
+        public TypeDescriptor AddProperty(PropertyDescriptor property)
+        {
+            properties ??= new();
+            properties.Add(property);
+            return this;
+        }
+    }
+
+    public class PropertyDescriptor
+    {
+        public string name;
+        public Type type;
+        public List<CustomAttributeBuilder> attributes;
+
+
+        public PropertyDescriptor() { }
+        public PropertyDescriptor(string name, Type type) { this.name = name; this.type = type; }
+
+        public static PropertyDescriptor New<ValueType>(string name) => new PropertyDescriptor(name, typeof(ValueType));
+
+
+        public PropertyDescriptor AddAttribute<CustomAttribute>(
+            IEnumerable<(Type type, object value)> constructorArgs = null
+            , IEnumerable<(string name, object value)> propertyValues = null
+            )
+            where CustomAttribute : Attribute
+        {
+            attributes ??= new();
+            attributes.Add(EntityGenerator.GetAttributeBuilder<CustomAttribute>(constructorArgs, propertyValues));
+            return this;
+        }
+        public PropertyDescriptor AddAttribute<CustomAttribute>(IEnumerable<object> constructorArgs, IEnumerable<(string name, object value)> propertyValues = null)
+           where CustomAttribute : Attribute
+           => AddAttribute<CustomAttribute>(constructorArgs.Select(value => (value.GetType(), value)), propertyValues);
+    }
+    #endregion
+
+}

+ 69 - 0
src/Vitorm.EntityGenerate/EntityGenerate/EntityHelp.cs

@@ -0,0 +1,69 @@
+#region << Version-v3 >>
+/*
+ * ========================================================================
+ * Version: v3
+ * Time   : 2024-07-28
+ * Author : lith
+ * Email  : LithWang@outlook.com
+ * Remarks: 
+ * ========================================================================
+*/
+#endregion
+
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+using Vit.Db.Module.Schema;
+using Vit.DynamicCompile.EntityGenerate;
+
+namespace Vitorm.EntityGenerate
+{
+    public class EntityHelp
+    {
+        public static Type GenerateEntityBySchema(TableSchema tableSchema, string entityNamespace, string typeName = null, string moduleName = "Main", string assemblyName = "DynamicEntity")
+        {
+            typeName ??= tableSchema.table_name;
+
+            // #1
+            var typeDescriptor = new TypeDescriptor
+            {
+                assemblyName = assemblyName,
+                moduleName = moduleName,
+                typeName = entityNamespace + "." + typeName,
+            };
+
+            // #2 Type Attribute
+            if (tableSchema.schema_name == null)
+            {
+                typeDescriptor.AddAttribute<TableAttribute>(constructorArgs: new object[] { tableSchema.table_name });
+            }
+            else
+            {
+                typeDescriptor.AddAttribute<TableAttribute>(constructorArgs: new object[] { tableSchema.table_name }, propertyValues: new[] { ("Schema", (object)tableSchema.schema_name) });
+            }
+
+
+            // #3 properties
+            {
+                tableSchema.columns.ForEach(column =>
+                {
+                    var property = new PropertyDescriptor(column.column_name, column.column_clr_type);
+
+                    //property.AddAttribute<RequiredAttribute>();
+
+                    if (column.primary_key == 1) property.AddAttribute<KeyAttribute>();
+
+                    if (column.autoincrement == 1) property.AddAttribute<DatabaseGeneratedAttribute>(constructorArgs: new object[] { DatabaseGeneratedOption.Identity });
+
+                    if (!string.IsNullOrEmpty(column.column_type))
+                        property.AddAttribute<ColumnAttribute>(constructorArgs: new object[] { column.column_name }, propertyValues: new (string, object)[] { ("TypeName", column.column_type) });
+
+                    typeDescriptor.AddProperty(property);
+                });
+            }
+
+            return EntityGenerator.CreateType(typeDescriptor);
+        }
+    }
+}

+ 167 - 0
src/Vitorm.EntityGenerate/Extensions/IDbSet_Extensions.cs

@@ -0,0 +1,167 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+using Vit.Core.Module.Serialization;
+
+using EntityType = System.Object;
+namespace Vitorm
+{
+    public static partial class IDbSet_Extensions
+    {
+        #region #0 Schema :  Create Drop
+        public static void TryCreateTable(this IDbSet data)
+        {
+            var entityType = data.entityDescriptor.entityType;
+
+            var methodInfo = new Action<IDbSet>(TryCreateTable<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            methodInfo.Invoke(null, new object[] { data });
+        }
+        public static void TryDropTable(this IDbSet data)
+        {
+            var entityType = data.entityDescriptor.entityType;
+
+            var methodInfo = new Action<IDbSet>(TryDropTable<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            methodInfo.Invoke(null, new object[] { data });
+        }
+
+        #endregion
+
+        #region #1 Create :  Add AddRange
+        public static object Add(this IDbSet data, object entity)
+        {
+            if (entity == null) return null;
+
+            var entityType = data.entityDescriptor.entityType;
+            if (!entityType.IsInstanceOfType(entity)) entity = Json.Deserialize(Json.Serialize(entity), entityType);
+
+            var methodInfo = new Func<IDbSet, EntityType, EntityType>(Add<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return methodInfo.Invoke(null, new object[] { data, entity });
+        }
+        public static void AddRange(this IDbSet data, object entities)
+        {
+            if (entities == null) return;
+            var entityType = data.entityDescriptor.entityType;
+            var entityListType = typeof(IEnumerable<>).MakeGenericType(entityType);
+            if (!entityListType.IsAssignableFrom(entities.GetType())) entities = Json.Deserialize(Json.Serialize(entities), typeof(List<>).MakeGenericType(entityType));
+
+            var methodInfo = new Action<IDbSet, IEnumerable<EntityType>>(AddRange<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            methodInfo.Invoke(null, new object[] { data, entities });
+        }
+        #endregion
+
+
+
+
+        #region #2 Retrieve : Get Query
+
+        public static object Get(this IDbSet data, object keyValue)
+        {
+            var entityType = data.entityDescriptor.entityType;
+            var methodInfo = new Func<IDbSet, object, EntityType>(Get<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return methodInfo.Invoke(null, new object[] { data, keyValue });
+        }
+        public static IQueryable Query(this IDbSet data)
+        {
+            var entityType = data.entityDescriptor.entityType;
+
+            var methodInfo = new Func<IDbSet, IQueryable<EntityType>>(Query<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return methodInfo.Invoke(null, new object[] { data }) as IQueryable;
+        }
+        #endregion
+
+
+        #region #3 Update: Update UpdateRange
+        public static int Update(this IDbSet data, object entity)
+        {
+            if (entity == null) return default;
+
+            var entityType = data.entityDescriptor.entityType;
+            if (!entityType.IsInstanceOfType(entity)) entity = Json.Deserialize(Json.Serialize(entity), entityType);
+
+            var methodInfo = new Func<IDbSet, EntityType, int>(Update<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return (int)methodInfo.Invoke(null, new object[] { data, entity });
+        }
+        public static int UpdateRange(this IDbSet data, object entities)
+        {
+            if (entities == null) return default;
+            var entityType = data.entityDescriptor.entityType;
+            var entityListType = typeof(IEnumerable<>).MakeGenericType(entityType);
+            if (!entityListType.IsAssignableFrom(entities.GetType())) entities = Json.Deserialize(Json.Serialize(entities), typeof(List<>).MakeGenericType(entityType));
+
+            var methodInfo = new Func<IDbSet, IEnumerable<EntityType>, int>(UpdateRange<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return (int)methodInfo.Invoke(null, new object[] { data, entities });
+        }
+        #endregion
+
+
+        #region #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
+        public static int Delete(this IDbSet data, object entity)
+        {
+            if (entity == null) return default;
+
+            var entityType = data.entityDescriptor.entityType;
+            if (!entityType.IsInstanceOfType(entity)) entity = Json.Deserialize(Json.Serialize(entity), entityType);
+
+            var methodInfo = new Func<IDbSet, EntityType, int>(Delete<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return (int)methodInfo.Invoke(null, new object[] { data, entity });
+        }
+        public static int DeleteRange(this IDbSet data, object entities)
+        {
+            if (entities == null) return default;
+            var entityType = data.entityDescriptor.entityType;
+            var entityListType = typeof(IEnumerable<>).MakeGenericType(entityType);
+            if (!entityListType.IsAssignableFrom(entities.GetType())) entities = Json.Deserialize(Json.Serialize(entities), typeof(List<>).MakeGenericType(entityType));
+
+            var methodInfo = new Func<IDbSet, IEnumerable<EntityType>, int>(DeleteRange<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return (int)methodInfo.Invoke(null, new object[] { data, entities });
+        }
+
+        public static int DeleteByKey(this IDbSet data, object keyValue)
+        {
+            if (keyValue == null) return default;
+
+            var entityType = data.entityDescriptor.entityType;
+
+            var methodInfo = new Func<IDbSet, object, int>(DeleteByKey<EntityType>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType);
+            return (int)methodInfo.Invoke(null, new object[] { data, keyValue });
+        }
+        public static int DeleteByKeys(this IDbSet data, object keys)
+        {
+            if (keys == null) return default;
+
+            var entityType = data.entityDescriptor.entityType;
+            var keyType = TypeUtil.GetElementType(keys.GetType());
+
+            var methodInfo = new Func<IDbSet, IEnumerable<int>, int>(DeleteByKeys<EntityType, int>)
+                    .GetMethodInfo().GetGenericMethodDefinition()
+                    .MakeGenericMethod(entityType, keyType);
+            return (int)methodInfo.Invoke(null, new object[] { data, keys });
+        }
+        #endregion
+
+    }
+}

+ 39 - 0
src/Vitorm.EntityGenerate/Extensions/IDbSet_Extensions_Origin.cs

@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Linq;
+namespace Vitorm
+{
+    public static partial class IDbSet_Extensions
+    {
+        // #0 Schema :  Create Drop
+        private static void TryCreateTable<Entity>(this IDbSet data) => (data as DbSet<Entity>).TryCreateTable();
+        private static void TryDropTable<Entity>(this IDbSet data) => (data as DbSet<Entity>).TryDropTable();
+
+
+        // #1 Create :  Add AddRange
+        private static Entity Add<Entity>(this IDbSet data, Entity entity) => (data as DbSet<Entity>).Add(entity);
+        private static void AddRange<Entity>(this IDbSet data, IEnumerable<Entity> entities) => (data as DbSet<Entity>).AddRange(entities);
+
+
+
+
+        // #2 Retrieve : Get Query
+        private static Entity Get<Entity>(this IDbSet data, object keyValue) => (data as DbSet<Entity>).Get(keyValue);
+        private static IQueryable<Entity> Query<Entity>(this IDbSet data) => (data as DbSet<Entity>).Query();
+
+
+        // #3 Update: Update UpdateRange
+        private static int Update<Entity>(this IDbSet data, Entity entity) => (data as DbSet<Entity>).Update(entity);
+        private static int UpdateRange<Entity>(this IDbSet data, IEnumerable<Entity> entities) => (data as DbSet<Entity>).UpdateRange(entities);
+
+
+        // #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
+        private static int Delete<Entity>(this IDbSet data, Entity entity) => (data as DbSet<Entity>).Delete(entity);
+        private static int DeleteRange<Entity>(this IDbSet data, IEnumerable<Entity> entities) => (data as DbSet<Entity>).DeleteRange(entities);
+
+        private static int DeleteByKey<Entity>(this IDbSet data, object keyValue) => (data as DbSet<Entity>).DeleteByKey(keyValue);
+        private static int DeleteByKeys<Entity, Key>(this IDbSet data, IEnumerable<Key> keys) => (data as DbSet<Entity>).DeleteByKeys(keys);
+
+
+
+    }
+}

+ 41 - 0
src/Vitorm.EntityGenerate/Extensions/SqlDbContext_EntityType_Extensions.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Linq;
+
+using Vit.Extensions.Db_Extensions;
+
+using Vitorm.EntityGenerate;
+using Vitorm.Sql;
+
+namespace Vitorm
+{
+    public static partial class SqlDbContext_EntityType_Extensions
+    {
+        public static Type GenerateEntityType(this SqlDbContext dbContext, string entityNamespace, string tableName, string schemaName = null)
+        {
+            var dbConn = dbContext.dbConnection;
+            var tableSchema = dbConn.GetSchema(new[] { tableName }).First(m => string.IsNullOrEmpty(schemaName) || schemaName.Equals(m.schema_name, StringComparison.OrdinalIgnoreCase));
+            var entityType = EntityHelp.GenerateEntityBySchema(tableSchema, entityNamespace);
+            return entityType;
+        }
+
+        public static IDbSet GenerateDbSet(this SqlDbContext dbContext, string entityNamespace, string tableName, string schemaName = null, bool cacheEntity = false)
+        {
+            var entityType = GenerateEntityType(dbContext, entityNamespace, tableName, schemaName);
+
+            IDbSet dbSet;
+
+            if (cacheEntity)
+            {
+                dbSet = dbContext.DbSet(entityType);
+            }
+            else
+            {
+                var entityDescriptor = dbContext.entityLoader.LoadDescriptorWithoutCache(entityType);
+                dbSet = Vitorm.Sql.DbSetConstructor.CreateDbSet(dbContext, entityDescriptor);
+            }
+            return dbSet;
+        }
+
+
+    }
+}

+ 72 - 0
src/Vitorm.EntityGenerate/README.md

@@ -0,0 +1,72 @@
+
+# Vitorm.EntityGenerate
+Library to generate Entity Type from Database
+> source address: [https://github.com/VitormLib/Vitorm](https://github.com/VitormLib/Vitorm "https://github.com/VitormLib/Vitorm/tree/master/src/Vitorm.EntityGenerate")        
+
+![](https://img.shields.io/github/license/VitormLib/Vitorm.svg)  
+![](https://img.shields.io/github/repo-size/VitormLib/Vitorm.svg)  ![](https://img.shields.io/github/last-commit/VitormLib/Vitorm.svg)  
+ 
+
+| Build | NuGet |
+| -------- | -------- |
+|![](https://github.com/VitormLib/Vitorm/workflows/ki_devops3/badge.svg) | [![](https://img.shields.io/nuget/v/Vitorm.EntityGenerate.svg)](https://www.nuget.org/packages/Vitorm.EntityGenerate) ![](https://img.shields.io/nuget/dt/Vitorm.EntityGenerate.svg) |
+
+
+
+
+# Vitorm.EntityGenerate Documentation    
+ 
+## Installation    
+Before using , install the necessary package:
+``` bash
+dotnet add package Vitorm.EntityGenerate
+dotnet add package Vitorm.Sqlite
+```
+
+## Minimum viable demo
+> The Entity for table GeneratedUser does not exist, Vitorm.EntityGenerate can help us generate an temporary one.     
+
+``` csharp
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Vitorm.Sql;
+namespace Vitorm.MsTest.Sqlite
+{
+    [TestClass]
+    public partial class EntityGenerate_Test
+    {
+        [TestMethod]
+        public void Test()
+        {
+            // #1 init
+            var entityNamespace = "Vitorm.MsTest.Sqlite";
+            var guid = Guid.NewGuid().ToString();
+            var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{guid}.sqlite.db");
+            var connectionString = $"data source={filePath}";
+
+            using var dbContext = new SqlDbContext();
+            dbContext.UseSqlite(connectionString);
+
+            dbContext.Execute(@"
+DROP TABLE if exists GeneratedUser;
+CREATE TABLE GeneratedUser(id integer NOT NULL PRIMARY KEY,  name text DEFAULT NULL);
+Insert into GeneratedUser(id,name) values(1,'u146');
+");
+
+            // #2 test
+            var dbSet = dbContext.GenerateDbSet(entityNamespace: entityNamespace, tableName: "GeneratedUser");
+            var entityType = dbSet.entityDescriptor.entityType;
+
+            // GetEntity
+            dynamic user = dbSet.Get(1);
+            string name = user.name;
+            Assert.AreEqual("u146", name);
+
+            BaseTest.TestDbSet(dbSet);
+        }
+    }
+}
+
+```
+ 
+
+[Test Example](https://github.com/VitormLib/Vitorm/tree/master/test/Vitorm.EntityGenerate.MsTest)    

+ 44 - 0
src/Vitorm.EntityGenerate/Vitorm.EntityGenerate.csproj

@@ -0,0 +1,44 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <pack>nuget</pack>
+    </PropertyGroup>
+
+    <PropertyGroup>
+        <TargetFramework>netstandard2.0</TargetFramework>
+        <Version>2.0.2</Version>
+        <LangVersion>9.0</LangVersion>
+    </PropertyGroup>
+
+    <PropertyGroup>
+        <Authors>Lith</Authors>
+        <Description>Generage Entity Type from Database</Description>
+        <PackageProjectUrl>https://github.com/VitormLib/Vitorm</PackageProjectUrl>
+        <PackageIcon>vitorm_logo_v1.png</PackageIcon>
+        <PackageReadmeFile>README.md</PackageReadmeFile>
+        <PackageTags>orm vitorm database mysql sqlserver sqlite Entity DbFirst</PackageTags>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <None Include="..\..\doc\vitorm_logo_v1.png">
+            <Pack>True</Pack>
+            <PackagePath>\</PackagePath>
+        </None>
+        <None Update="README.md">
+            <Pack>True</Pack>
+            <PackagePath>\</PackagePath>
+        </None>
+    </ItemGroup>
+
+    <ItemGroup>
+        <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
+        <PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
+        <PackageReference Include="Vit.Core" Version="2.2.0" />
+        <PackageReference Include="Vit.Db" Version="3.0.0" />
+    </ItemGroup>
+
+    <ItemGroup>
+        <ProjectReference Include="..\Vitorm.Data\Vitorm.Data.csproj" />
+    </ItemGroup>
+
+</Project>

+ 1 - 1
src/Vitorm.MySql/Vitorm.MySql.csproj

@@ -6,7 +6,7 @@
 
     <PropertyGroup>
         <TargetFramework>netstandard2.0</TargetFramework>
-        <Version>2.0.1</Version>
+        <Version>2.0.2</Version>
         <LangVersion>9.0</LangVersion>
     </PropertyGroup>
 

+ 1 - 1
src/Vitorm.SqlServer/SqlTranslateService.cs

@@ -200,7 +200,7 @@ namespace Vitorm.SqlServer
             /* //sql
 if object_id(N'[dbo].[User]', N'U') is null
     CREATE TABLE [dbo].[User] (
-      id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+      id int NOT NULL PRIMARY KEY IDENTITY(1,1),
       name varchar(100) DEFAULT NULL,
       birth date DEFAULT NULL,
       fatherId int DEFAULT NULL,

+ 1 - 1
src/Vitorm.SqlServer/Vitorm.SqlServer.csproj

@@ -6,7 +6,7 @@
 
     <PropertyGroup>
         <TargetFramework>netstandard2.0</TargetFramework>
-        <Version>2.0.1</Version>
+        <Version>2.0.2</Version>
         <LangVersion>9.0</LangVersion>
     </PropertyGroup>
 

+ 2 - 2
src/Vitorm.Sqlite/Vitorm.Sqlite.csproj

@@ -6,7 +6,7 @@
 
     <PropertyGroup>
         <TargetFramework>netstandard2.0</TargetFramework>
-        <Version>2.0.1</Version>
+        <Version>2.0.2</Version>
         <LangVersion>9.0</LangVersion>
     </PropertyGroup>
 
@@ -31,7 +31,7 @@
     </ItemGroup>
 
     <ItemGroup>
-        <PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.6" />
+        <PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.7" />
     </ItemGroup>
 
     <ItemGroup>

+ 31 - 27
src/Vitorm/DbContext.cs

@@ -32,6 +32,36 @@ namespace Vitorm
         #endregion
 
 
+        #region DbSet
+        protected IDbSet DefaultDbSetCreator(IEntityDescriptor entityDescriptor)
+        {
+            return DbSetConstructor.CreateDbSet(this, entityDescriptor);
+        }
+
+        protected virtual Func<IEntityDescriptor, IDbSet> dbSetCreator { set; get; }
+
+        protected Dictionary<Type, IDbSet> dbSetMap = null;
+
+        public virtual IDbSet DbSet(Type entityType)
+        {
+            if (dbSetMap?.TryGetValue(entityType, out var dbSet) == true) return dbSet;
+
+            var entityDescriptor = GetEntityDescriptor(entityType);
+
+            dbSet = dbSetCreator(entityDescriptor);
+            if (dbSet == null) return null;
+
+            dbSetMap ??= new();
+            dbSetMap[entityType] = dbSet;
+            return dbSet;
+        }
+        public virtual IDbSet CreateDbSet(IEntityDescriptor entityDescriptor) => dbSetCreator(entityDescriptor);
+        public virtual IDbSet<Entity> DbSet<Entity>()
+        {
+            return DbSet(typeof(Entity)) as IDbSet<Entity>;
+        }
+        #endregion
+
 
         #region EntityLoader
 
@@ -48,6 +78,7 @@ namespace Vitorm
         #endregion
 
 
+
         #region ChangeTable ChangeTableBack
 
         public virtual IDbSet ChangeTable(Type entityType, string tableName)
@@ -73,34 +104,7 @@ namespace Vitorm
 
 
 
-        #region DbSet
-
-        protected IDbSet DefaultDbSetCreator(Type entityType)
-        {
-            var entityDescriptor = GetEntityDescriptor(entityType);
-            return DbSetConstructor.CreateDbSet(this, entityType, entityDescriptor);
-        }
-
-        protected virtual Func<Type, IDbSet> dbSetCreator { set; get; }
-
-        protected Dictionary<Type, IDbSet> dbSetMap = null;
-
-        public virtual IDbSet DbSet(Type entityType)
-        {
-            if (dbSetMap?.TryGetValue(entityType, out var dbSet) == true) return dbSet;
-
-            dbSet = dbSetCreator(entityType);
-            if (dbSet == null) return null;
 
-            dbSetMap ??= new();
-            dbSetMap[entityType] = dbSet;
-            return dbSet;
-        }
-        public virtual DbSet<Entity> DbSet<Entity>()
-        {
-            return DbSet(typeof(Entity)) as DbSet<Entity>;
-        }
-        #endregion
 
 
 

+ 11 - 13
src/Vitorm/DbSet.cs

@@ -9,15 +9,15 @@ namespace Vitorm
 {
     public class DbSetConstructor
     {
-        public static IDbSet CreateDbSet(DbContext dbContext, Type entityType, IEntityDescriptor entityDescriptor)
+        public static IDbSet CreateDbSet(DbContext dbContext, IEntityDescriptor entityDescriptor)
         {
-            return _CreateDbSet.MakeGenericMethod(entityType)
+            return _CreateDbSet.MakeGenericMethod(entityDescriptor.entityType)
                      .Invoke(null, new object[] { dbContext, entityDescriptor }) as IDbSet;
         }
 
         static readonly MethodInfo _CreateDbSet = new Func<DbContext, IEntityDescriptor, IDbSet>(CreateDbSet<object>)
                    .Method.GetGenericMethodDefinition();
-        public static IDbSet CreateDbSet<Entity>(DbContext dbContext, IEntityDescriptor entityDescriptor)
+        public static IDbSet<Entity> CreateDbSet<Entity>(DbContext dbContext, IEntityDescriptor entityDescriptor)
         {
             return new DbSet<Entity>(dbContext, entityDescriptor);
         }
@@ -25,9 +25,9 @@ namespace Vitorm
     }
 
 
-    public class DbSet<Entity> : IDbSet
+    public class DbSet<Entity> : IDbSet<Entity>
     {
-        protected DbContext dbContext;
+        public virtual DbContext dbContext { get; protected set; }
 
         protected IEntityDescriptor _entityDescriptor;
         public virtual IEntityDescriptor entityDescriptor => _entityDescriptor;
@@ -39,39 +39,37 @@ namespace Vitorm
             this._entityDescriptor = entityDescriptor;
         }
 
-
+        // #0 Schema :  ChangeTable
         public virtual IEntityDescriptor ChangeTable(string tableName) => _entityDescriptor = _entityDescriptor.WithTable(tableName);
         public virtual IEntityDescriptor ChangeTableBack() => _entityDescriptor = _entityDescriptor.GetOriginEntityDescriptor();
 
 
-
+        // #0 Schema :  Create Drop
         public virtual void TryCreateTable() => dbContext.TryCreateTable<Entity>();
         public virtual void TryDropTable() => dbContext.TryDropTable<Entity>();
 
 
-
+        // #1 Create :  Add AddRange
         public virtual Entity Add(Entity entity) => dbContext.Add(entity);
         public virtual void AddRange(IEnumerable<Entity> entities) => dbContext.AddRange(entities);
 
 
-
-
+        // #2 Retrieve : Get Query
         public virtual Entity Get(object keyValue) => dbContext.Get<Entity>(keyValue);
         public virtual IQueryable<Entity> Query() => dbContext.Query<Entity>();
 
 
-
+        // #3 Update: Update UpdateRange
         public virtual int Update(Entity entity) => dbContext.Update<Entity>(entity);
         public virtual int UpdateRange(IEnumerable<Entity> entities) => dbContext.UpdateRange<Entity>(entities);
 
 
-
+        // #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
         public virtual int Delete(Entity entity) => dbContext.Delete<Entity>(entity);
         public virtual int DeleteRange(IEnumerable<Entity> entities) => dbContext.DeleteRange<Entity>(entities);
         public virtual int DeleteByKey(object keyValue) => dbContext.DeleteByKey<Entity>(keyValue);
         public virtual int DeleteByKeys<Key>(IEnumerable<Key> keys) => dbContext.DeleteByKeys<Entity, Key>(keys);
 
 
-
     }
 }

+ 4 - 4
src/Vitorm/Entity/DataAnnotations/EntityLoader.cs

@@ -13,10 +13,10 @@ namespace Vitorm.Entity.DataAnnotations
         {
         }
 
-        public IEntityDescriptor LoadDescriptor(Type entityType)
-        {
-            return LoadFromType(entityType);
-        }
+        public IEntityDescriptor LoadDescriptor(Type entityType) => LoadFromType(entityType);
+
+        public IEntityDescriptor LoadDescriptorWithoutCache(Type entityType) => LoadFromType(entityType);
+
 
         public static bool GetTableName(Type entityType, out string tableName, out string schema)
         {

+ 9 - 2
src/Vitorm/Entity/Loader/DefaultEntityLoader.cs

@@ -27,12 +27,19 @@ namespace Vitorm.Entity.Loader
         public IEntityDescriptor LoadDescriptor(Type entityType)
         {
             if (descriptorCache.TryGetValue(entityType, out var entityDescriptor)) return entityDescriptor;
+            entityDescriptor = LoadDescriptorWithoutCache(entityType);
+            if (entityDescriptor != null)
+                descriptorCache[entityType] = entityDescriptor;
+            return entityDescriptor;
+        }
+
+        public IEntityDescriptor LoadDescriptorWithoutCache(Type entityType)
+        {
             foreach (var loader in loaders)
             {
-                entityDescriptor = loader.LoadDescriptor(entityType);
+                var entityDescriptor = loader.LoadDescriptor(entityType);
                 if (entityDescriptor != null)
                 {
-                    descriptorCache[entityType] = entityDescriptor;
                     return entityDescriptor;
                 }
             }

+ 1 - 0
src/Vitorm/Entity/Loader/IEntityLoader.cs

@@ -6,5 +6,6 @@ namespace Vitorm.Entity.Loader
     {
         void CleanCache();
         IEntityDescriptor LoadDescriptor(Type entityType);
+        IEntityDescriptor LoadDescriptorWithoutCache(Type entityType);
     }
 }

+ 3 - 1
src/Vitorm/Entity/LoaderAttribute/EntityLoaderFromAttribute.cs

@@ -11,7 +11,9 @@ namespace Vitorm.Entity.LoaderAttribute
         {
         }
 
-        public IEntityDescriptor LoadDescriptor(Type entityType)
+        public IEntityDescriptor LoadDescriptor(Type entityType) => LoadDescriptorWithoutCache(entityType);
+
+        public IEntityDescriptor LoadDescriptorWithoutCache(Type entityType)
         {
             var loaderType = entityType.GetCustomAttribute<EntityLoaderAttribute>()?.Loader;
             if (loaderType == null || !typeof(IEntityLoader).IsAssignableFrom(loaderType)) return null;

+ 36 - 1
src/Vitorm/IDbSet.cs

@@ -1,11 +1,46 @@
-using Vitorm.Entity;
+using System.Collections.Generic;
+using System.Linq;
+
+using Vitorm.Entity;
 
 namespace Vitorm
 {
     public interface IDbSet
     {
         IEntityDescriptor entityDescriptor { get; }
+        DbContext dbContext { get; }
+
+        // #0 Schema :  ChangeTable
         IEntityDescriptor ChangeTable(string tableName);
         IEntityDescriptor ChangeTableBack();
+
+        // #0 Schema :  Create Drop
+        void TryCreateTable();
+        void TryDropTable();
+    }
+
+    public interface IDbSet<Entity> : IDbSet
+    {
+        // #1 Create :  Add AddRange
+        Entity Add(Entity entity);
+        void AddRange(IEnumerable<Entity> entities);
+
+        // #2 Retrieve : Get Query
+        Entity Get(object keyValue);
+        IQueryable<Entity> Query();
+
+
+        // #3 Update: Update UpdateRange
+        int Update(Entity entity);
+        int UpdateRange(IEnumerable<Entity> entities);
+
+
+        // #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
+        int Delete(Entity entity);
+        int DeleteRange(IEnumerable<Entity> entities);
+        int DeleteByKey(object keyValue);
+        int DeleteByKeys<Key>(IEnumerable<Key> keys);
+
+
     }
 }

+ 1 - 1
src/Vitorm/Sql/DbConnectionProvider.cs

@@ -42,7 +42,7 @@ namespace Vitorm.Sql
         public virtual string dbHashCode => connectionString.GetHashCode().ToString();
 
 
-        public IDbConnection CreaeteDbConnection() => createDbConnection(connectionString);
+        public IDbConnection CreateDbConnection() => createDbConnection(connectionString);
         public IDbConnection CreateReadOnlyDbConnection() => ableToCreateReadOnly ? createDbConnection(readOnlyConnectionString) : null;
 
         public virtual string databaseName => getDatabaseName(connectionString ?? readOnlyConnectionString);

+ 47 - 261
src/Vitorm/Sql/SqlDbContext.cs

@@ -7,6 +7,7 @@ using System.Linq.Expressions;
 using Vit.Linq;
 using Vit.Linq.ExpressionTree.ComponentModel;
 
+using Vitorm.Entity;
 using Vitorm.Sql.DataReader.EntityReader;
 using Vitorm.Sql.SqlTranslate;
 using Vitorm.Sql.Transaction;
@@ -16,6 +17,23 @@ namespace Vitorm.Sql
 {
     public partial class SqlDbContext : DbContext
     {
+        public SqlDbContext()
+        {
+            dbSetCreator = DefaultDbSetCreator;
+        }
+
+        #region DbSet
+        protected IDbSet DefaultDbSetCreator(IEntityDescriptor entityDescriptor)
+        {
+            return DbSetConstructor.CreateDbSet(this, entityDescriptor);
+        }
+
+        #endregion
+
+
+
+        #region EntityReader
+
 
         /// <summary>
         /// Vitorm.Sql.DataReader.EntityReader.IEntityReader
@@ -36,8 +54,11 @@ namespace Vitorm.Sql
         {
             entityReaderType = typeof(EntityReader);
         }
+        #endregion
 
 
+        #region dbConnection
+        protected DbConnectionProvider dbConnectionProvider;
         protected IDbConnection _dbConnection;
         protected IDbConnection _readOnlyDbConnection;
         public override void Dispose()
@@ -70,23 +91,27 @@ namespace Vitorm.Sql
                 }
             }
         }
-        public virtual IDbConnection dbConnection => _dbConnection ??= dbConnectionProvider.CreaeteDbConnection();
+        public virtual IDbConnection dbConnection => _dbConnection ??= dbConnectionProvider.CreateDbConnection();
         public virtual IDbConnection readOnlyDbConnection
             => _readOnlyDbConnection ??
                 (dbConnectionProvider.ableToCreateReadOnly ? (_readOnlyDbConnection = dbConnectionProvider.CreateReadOnlyDbConnection()) : dbConnection);
 
-
-        public virtual ISqlTranslateService sqlTranslateService { get; private set; }
-
-
-        protected DbConnectionProvider dbConnectionProvider;
-
         /// <summary>
         /// to identify whether contexts are from the same database
         /// </summary>
         protected virtual string dbGroupName => "SqlDbSet_" + dbConnectionProvider.dbHashCode;
         public virtual string databaseName => dbConnectionProvider.databaseName;
 
+        public virtual void ChangeDatabase(string databaseName)
+        {
+            if (_dbConnection != null || _readOnlyDbConnection != null) throw new InvalidOperationException("can not change database after connected, please try in an new DbContext.");
+
+            dbConnectionProvider = dbConnectionProvider.WithDatabase(databaseName);
+        }
+
+        #endregion
+
+        public virtual ISqlTranslateService sqlTranslateService { get; private set; }
 
         public virtual void Init(ISqlTranslateService sqlTranslateService, DbConnectionProvider dbConnectionProvider, SqlExecutor sqlExecutor = null, Dictionary<string, object> extraConfig = null)
         {
@@ -108,180 +133,24 @@ namespace Vitorm.Sql
         }
 
 
-        public virtual void ChangeDatabase(string databaseName)
-        {
-            if (_dbConnection != null || _readOnlyDbConnection != null) throw new InvalidOperationException("cna not change database after connected, please try in an new DbContext.");
-
-            dbConnectionProvider = dbConnectionProvider.WithDatabase(databaseName);
-        }
-
-
-        #region #0 Schema :  Create Drop
-
-        public override void TryCreateTable<Entity>()
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-
-            string sql = sqlTranslateService.PrepareTryCreateTable(entityDescriptor);
-            Execute(sql: sql);
-        }
-        public override void TryDropTable<Entity>()
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-
-            string sql = sqlTranslateService.PrepareTryDropTable(entityDescriptor);
-            Execute(sql: sql);
-        }
-        #endregion
-
-
-        #region #1 Create :  Add AddRange
-
-        public override Entity Add<Entity>(Entity entity)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-            SqlTranslateArgument arg = new SqlTranslateArgument(this, entityDescriptor);
-
-            var addType = sqlTranslateService.Entity_GetAddType(arg, entity);
-            //if (addType == EAddType.unexpectedEmptyKey) throw new ArgumentException("Key could not be empty.");
-
-
-
 
-            if (addType == EAddType.identityKey)
-            {
-                // #1 prepare sql
-                (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareIdentityAdd(arg);
 
-                // #2 get sql params
-                var sqlParam = GetSqlParams(entity);
+        // #0 Schema :  Create Drop
+        public override void TryCreateTable<Entity>() => DbSet<Entity>().TryCreateTable();
+        public override void TryDropTable<Entity>() => DbSet<Entity>().TryDropTable();
 
-                // #3 add
-                var newKeyValue = ExecuteScalar(sql: sql, param: sqlParam);
 
-                // #4 set key value to entity
-                var keyType = TypeUtil.GetUnderlyingType(entityDescriptor.key.type);
-                newKeyValue = TypeUtil.ConvertToUnderlyingType(newKeyValue, keyType);
-                if (newKeyValue != null)
-                {
-                    entityDescriptor.key.SetValue(entity, newKeyValue);
-                }
-            }
-            else
-            {
-                // #1 prepare sql
-                (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareAdd(arg);
+        // #1 Create :  Add AddRange
+        public override Entity Add<Entity>(Entity entity) => DbSet<Entity>().Add(entity);
+        public override void AddRange<Entity>(IEnumerable<Entity> entities) => DbSet<Entity>().AddRange(entities);
 
-                // #2 get sql params
-                var sqlParam = GetSqlParams(entity);
-
-                // #3 add
-                Execute(sql: sql, param: sqlParam);
-            }
-
-            return entity;
-        }
-        public override void AddRange<Entity>(IEnumerable<Entity> entities)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-            SqlTranslateArgument arg = new SqlTranslateArgument(this, entityDescriptor);
-            List<(Entity entity, EAddType addType)> entityAndTypes = entities.Select(entity => (entity, sqlTranslateService.Entity_GetAddType(arg, entity))).ToList();
-            //if (entityAndTypes.Any(row => row.addType == EAddType.unexpectedEmptyKey)) throw new ArgumentException("Key could not be empty.");
-
-
-            var affectedRowCount = 0;
-
-            // #2 keyWithValue
-            {
-                var rows = entityAndTypes.Where(row => row.addType == EAddType.keyWithValue);
-                if (rows.Any())
-                {
-                    // ##1 prepare sql
-                    (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareAdd(arg);
-
-                    foreach ((var entity, _) in rows)
-                    {
-                        // #2 get sql params
-                        var sqlParam = GetSqlParams(entity);
-
-                        // #3 add
-                        Execute(sql: sql, param: sqlParam);
-                        affectedRowCount++;
-                    }
-                }
-            }
-
-            // #3 identityKey
-            {
-                var rows = entityAndTypes.Where(row => row.addType == EAddType.identityKey);
-                if (rows.Any())
-                {
-                    var keyType = TypeUtil.GetUnderlyingType(entityDescriptor.key.type);
-
-                    // ##1 prepare sql
-                    (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareIdentityAdd(arg);
-
-                    foreach ((var entity, _) in rows)
-                    {
-                        // ##2 get sql params
-                        var sqlParam = GetSqlParams(entity);
-
-                        // ##3 add
-                        var newKeyValue = ExecuteScalar(sql: sql, param: sqlParam);
-
-                        // ##4 set key value to entity
-                        newKeyValue = TypeUtil.ConvertToUnderlyingType(newKeyValue, keyType);
-                        if (newKeyValue != null)
-                        {
-                            entityDescriptor.key.SetValue(entity, newKeyValue);
-                        }
-
-                        affectedRowCount++;
-                    }
-                }
-            }
-        }
-
-        #endregion
 
 
 
         #region #2 Retrieve : Get Query
 
-        public override Entity Get<Entity>(object keyValue)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-            SqlTranslateArgument arg = new SqlTranslateArgument(this, entityDescriptor);
-
+        public override Entity Get<Entity>(object keyValue) => DbSet<Entity>().Get(keyValue);
 
-            // #1 prepare sql
-            string sql = sqlTranslateService.PrepareGet(arg);
-
-            // #2 get sql params
-            var sqlParam = new Dictionary<string, object>();
-            sqlParam[entityDescriptor.keyName] = keyValue;
-
-            // #3 execute
-            using var reader = ExecuteReader(sql: sql, param: sqlParam, useReadOnly: true);
-            if (reader.Read())
-            {
-                var entity = (Entity)Activator.CreateInstance(typeof(Entity));
-                foreach (var column in entityDescriptor.allColumns)
-                {
-                    var value = TypeUtil.ConvertToType(reader[column.columnName], column.type);
-                    if (value != null)
-                        column.SetValue(entity, value);
-                }
-                return entity;
-            }
-            return default;
-
-        }
 
         public override IQueryable<Entity> Query<Entity>()
         {
@@ -495,104 +364,21 @@ namespace Vitorm.Sql
 
 
 
-        #region #3 Update: Update UpdateRange
+        // #3 Update: Update UpdateRange
+        public override int Update<Entity>(Entity entity) => DbSet<Entity>().Update(entity);
 
-        public override int Update<Entity>(Entity entity)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-            SqlTranslateArgument arg = new SqlTranslateArgument(this, entityDescriptor);
+        public override int UpdateRange<Entity>(IEnumerable<Entity> entities) => DbSet<Entity>().UpdateRange(entities);
 
-            // #1 prepare sql
-            (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareUpdate(arg);
 
-            // #2 get sql params
-            var sqlParam = GetSqlParams(entity);
 
-            // #3 execute
-            var affectedRowCount = Execute(sql: sql, param: sqlParam);
+        // #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
+        public override int Delete<Entity>(Entity entity) => DbSet<Entity>().Delete(entity);
+        public override int DeleteRange<Entity>(IEnumerable<Entity> entities) => DbSet<Entity>().DeleteRange(entities);
 
-            return affectedRowCount;
+        public override int DeleteByKey<Entity>(object keyValue) => DbSet<Entity>().DeleteByKey(keyValue);
+        public override int DeleteByKeys<Entity, Key>(IEnumerable<Key> keys) => DbSet<Entity>().DeleteByKeys<Key>(keys);
 
-        }
 
-        public override int UpdateRange<Entity>(IEnumerable<Entity> entities)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-            SqlTranslateArgument arg = new SqlTranslateArgument(this, entityDescriptor);
-
-            // #1 prepare sql
-            (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareUpdate(arg);
-
-            // #2 execute
-            var affectedRowCount = 0;
-
-            foreach (var entity in entities)
-            {
-                var sqlParam = GetSqlParams(entity);
-                affectedRowCount += Execute(sql: sql, param: sqlParam);
-            }
-            return affectedRowCount;
-        }
-
-        #endregion
-
-
-        #region #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
-        public override int Delete<Entity>(Entity entity)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-
-            var key = entityDescriptor.key.GetValue(entity);
-            return DeleteByKey<Entity>(key);
-        }
-
-        public override int DeleteRange<Entity>(IEnumerable<Entity> entities)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-
-            var keys = entities.Select(entity => entityDescriptor.key.GetValue(entity)).ToList();
-            return DeleteByKeys<Entity, object>(keys);
-        }
-
-
-        public override int DeleteByKey<Entity>(object keyValue)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-            SqlTranslateArgument arg = new SqlTranslateArgument(this, entityDescriptor);
-
-            // #1 prepare sql
-            string sql = sqlTranslateService.PrepareDelete(arg);
-
-            // #2 get sql params
-            var sqlParam = new Dictionary<string, object>();
-            sqlParam[entityDescriptor.keyName] = keyValue;
-
-            // #3 execute
-            var affectedRowCount = Execute(sql: sql, param: sqlParam);
-
-            return affectedRowCount;
-
-        }
-        public override int DeleteByKeys<Entity, Key>(IEnumerable<Key> keys)
-        {
-            // #0 get arg
-            var entityDescriptor = GetEntityDescriptor(typeof(Entity));
-            SqlTranslateArgument arg = new SqlTranslateArgument(this, entityDescriptor);
-
-            // #1 prepare sql
-            var sql = sqlTranslateService.PrepareDeleteByKeys(arg, keys);
-
-            // #2 execute
-            var affectedRowCount = Execute(sql: sql, param: arg.sqlParam);
-            return affectedRowCount;
-        }
-
-        #endregion
 
 
         #region Transaction

+ 274 - 0
src/Vitorm/Sql/SqlDbSet.cs

@@ -0,0 +1,274 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+using Vitorm.Entity;
+using Vitorm.Sql.SqlTranslate;
+
+namespace Vitorm.Sql
+{
+    public class DbSetConstructor
+    {
+        public static IDbSet CreateDbSet(SqlDbContext dbContext, IEntityDescriptor entityDescriptor)
+        {
+            return _CreateDbSet.MakeGenericMethod(entityDescriptor.entityType)
+                     .Invoke(null, new object[] { dbContext, entityDescriptor }) as IDbSet;
+        }
+
+        static readonly MethodInfo _CreateDbSet = new Func<SqlDbContext, IEntityDescriptor, IDbSet>(CreateDbSet<object>)
+                   .Method.GetGenericMethodDefinition();
+        public static IDbSet<Entity> CreateDbSet<Entity>(SqlDbContext dbContext, IEntityDescriptor entityDescriptor)
+        {
+            return new SqlDbSet<Entity>(dbContext, entityDescriptor);
+        }
+
+    }
+
+
+    public class SqlDbSet<Entity> : DbSet<Entity>
+    {
+
+        public virtual SqlDbContext sqlDbContext => (SqlDbContext)dbContext;
+
+        public SqlDbSet(SqlDbContext dbContext, IEntityDescriptor entityDescriptor) : base(dbContext, entityDescriptor)
+        {
+        }
+
+        protected virtual ISqlTranslateService sqlTranslateService => sqlDbContext.sqlTranslateService;
+
+        #region #0 Schema :  Create Drop
+        public override void TryCreateTable()
+        {
+            string sql = sqlTranslateService.PrepareTryCreateTable(entityDescriptor);
+            sqlDbContext.Execute(sql: sql);
+        }
+        public override void TryDropTable()
+        {
+            string sql = sqlTranslateService.PrepareTryDropTable(entityDescriptor);
+            sqlDbContext.Execute(sql: sql);
+        }
+        #endregion
+
+
+        #region #1 Create :  Add AddRange
+        public override Entity Add(Entity entity)
+        {
+            SqlTranslateArgument arg = new SqlTranslateArgument(sqlDbContext, entityDescriptor);
+
+            var addType = sqlTranslateService.Entity_GetAddType(arg, entity);
+            //if (addType == EAddType.unexpectedEmptyKey) throw new ArgumentException("Key could not be empty.");
+
+            if (addType == EAddType.identityKey)
+            {
+                // #1 prepare sql
+                (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareIdentityAdd(arg);
+
+                // #2 get sql params
+                var sqlParam = GetSqlParams(entity);
+
+                // #3 add
+                var newKeyValue = sqlDbContext.ExecuteScalar(sql: sql, param: sqlParam);
+
+                // #4 set key value to entity
+                var keyType = TypeUtil.GetUnderlyingType(entityDescriptor.key.type);
+                newKeyValue = TypeUtil.ConvertToUnderlyingType(newKeyValue, keyType);
+                if (newKeyValue != null)
+                {
+                    entityDescriptor.key.SetValue(entity, newKeyValue);
+                }
+            }
+            else
+            {
+                // #1 prepare sql
+                (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareAdd(arg);
+
+                // #2 get sql params
+                var sqlParam = GetSqlParams(entity);
+
+                // #3 add
+                sqlDbContext.Execute(sql: sql, param: sqlParam);
+            }
+
+            return entity;
+        }
+        public override void AddRange(IEnumerable<Entity> entities)
+        {
+            // #0 get arg
+            SqlTranslateArgument arg = new SqlTranslateArgument(sqlDbContext, entityDescriptor);
+            List<(Entity entity, EAddType addType)> entityAndTypes = entities.Select(entity => (entity, sqlTranslateService.Entity_GetAddType(arg, entity))).ToList();
+            //if (entityAndTypes.Any(row => row.addType == EAddType.unexpectedEmptyKey)) throw new ArgumentException("Key could not be empty.");
+
+
+            var affectedRowCount = 0;
+
+            // #2 keyWithValue
+            {
+                var rows = entityAndTypes.Where(row => row.addType == EAddType.keyWithValue);
+                if (rows.Any())
+                {
+                    // ##1 prepare sql
+                    (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareAdd(arg);
+
+                    foreach ((var entity, _) in rows)
+                    {
+                        // #2 get sql params
+                        var sqlParam = GetSqlParams(entity);
+
+                        // #3 add
+                        sqlDbContext.Execute(sql: sql, param: sqlParam);
+                        affectedRowCount++;
+                    }
+                }
+            }
+
+            // #3 identityKey
+            {
+                var rows = entityAndTypes.Where(row => row.addType == EAddType.identityKey);
+                if (rows.Any())
+                {
+                    var keyType = TypeUtil.GetUnderlyingType(entityDescriptor.key.type);
+
+                    // ##1 prepare sql
+                    (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareIdentityAdd(arg);
+
+                    foreach ((var entity, _) in rows)
+                    {
+                        // ##2 get sql params
+                        var sqlParam = GetSqlParams(entity);
+
+                        // ##3 add
+                        var newKeyValue = sqlDbContext.ExecuteScalar(sql: sql, param: sqlParam);
+
+                        // ##4 set key value to entity
+                        newKeyValue = TypeUtil.ConvertToUnderlyingType(newKeyValue, keyType);
+                        if (newKeyValue != null)
+                        {
+                            entityDescriptor.key.SetValue(entity, newKeyValue);
+                        }
+
+                        affectedRowCount++;
+                    }
+                }
+            }
+        }
+        #endregion
+
+
+        #region #2 Retrieve : Get Query
+        public override Entity Get(object keyValue)
+        {
+            // #0 get arg
+            SqlTranslateArgument arg = new SqlTranslateArgument(sqlDbContext, entityDescriptor);
+
+
+            // #1 prepare sql
+            string sql = sqlTranslateService.PrepareGet(arg);
+
+            // #2 get sql params
+            var sqlParam = new Dictionary<string, object>();
+            sqlParam[entityDescriptor.keyName] = keyValue;
+
+            // #3 execute
+            using var reader = sqlDbContext.ExecuteReader(sql: sql, param: sqlParam, useReadOnly: true);
+            if (reader.Read())
+            {
+                var entity = (Entity)Activator.CreateInstance(entityDescriptor.entityType);
+                foreach (var column in entityDescriptor.allColumns)
+                {
+                    var value = TypeUtil.ConvertToType(reader[column.columnName], column.type);
+                    if (value != null)
+                        column.SetValue(entity, value);
+                }
+                return entity;
+            }
+            return default;
+
+        }
+        public override IQueryable<Entity> Query() => dbContext.Query<Entity>();
+        #endregion
+
+        #region #3 Update: Update UpdateRange
+        public override int Update(Entity entity)
+        {
+            // #0 get arg
+            SqlTranslateArgument arg = new SqlTranslateArgument(sqlDbContext, entityDescriptor);
+
+            // #1 prepare sql
+            (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareUpdate(arg);
+
+            // #2 get sql params
+            var sqlParam = GetSqlParams(entity);
+
+            // #3 execute
+            var affectedRowCount = sqlDbContext.Execute(sql: sql, param: sqlParam);
+
+            return affectedRowCount;
+        }
+        public override int UpdateRange(IEnumerable<Entity> entities)
+        {
+            // #0 get arg
+            SqlTranslateArgument arg = new SqlTranslateArgument(sqlDbContext, entityDescriptor);
+
+            // #1 prepare sql
+            (string sql, Func<object, Dictionary<string, object>> GetSqlParams) = sqlTranslateService.PrepareUpdate(arg);
+
+            // #2 execute
+            var affectedRowCount = 0;
+
+            foreach (var entity in entities)
+            {
+                var sqlParam = GetSqlParams(entity);
+                affectedRowCount += sqlDbContext.Execute(sql: sql, param: sqlParam);
+            }
+            return affectedRowCount;
+        }
+        #endregion
+
+        #region #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
+        public override int Delete(Entity entity)
+        {
+            var key = entityDescriptor.key.GetValue(entity);
+            return DeleteByKey(key);
+        }
+
+        public override int DeleteRange(IEnumerable<Entity> entities)
+        {
+            var keys = entities.Select(entity => entityDescriptor.key.GetValue(entity)).ToList();
+            return DeleteByKeys(keys);
+        }
+
+        public override int DeleteByKey(object keyValue)
+        {
+            // #0 get arg
+            SqlTranslateArgument arg = new SqlTranslateArgument(sqlDbContext, entityDescriptor);
+
+            // #1 prepare sql
+            string sql = sqlTranslateService.PrepareDelete(arg);
+
+            // #2 get sql params
+            var sqlParam = new Dictionary<string, object>();
+            sqlParam[entityDescriptor.keyName] = keyValue;
+
+            // #3 execute
+            var affectedRowCount = sqlDbContext.Execute(sql: sql, param: sqlParam);
+
+            return affectedRowCount;
+        }
+
+        public override int DeleteByKeys<Key>(IEnumerable<Key> keys)
+        {
+            // #0 get arg
+            SqlTranslateArgument arg = new SqlTranslateArgument(sqlDbContext, entityDescriptor);
+
+            // #1 prepare sql
+            var sql = sqlTranslateService.PrepareDeleteByKeys(arg, keys);
+
+            // #2 execute
+            var affectedRowCount = sqlDbContext.Execute(sql: sql, param: arg.sqlParam);
+            return affectedRowCount;
+        }
+        #endregion
+
+    }
+}

+ 2 - 3
src/Vitorm/Vitorm.csproj

@@ -6,7 +6,7 @@
 
     <PropertyGroup>
         <TargetFramework>netstandard2.0</TargetFramework>
-        <Version>2.0.1</Version>
+        <Version>2.0.2</Version>
         <LangVersion>9.0</LangVersion>
     </PropertyGroup>
 
@@ -32,8 +32,7 @@
 
     <ItemGroup>
         <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
-        <PackageReference Include="Vit.Linq" Version="3.0.1" />
+        <PackageReference Include="Vit.Linq" Version="3.0.2" />
     </ItemGroup>
 
-
 </Project>

+ 1 - 1
test/Vitorm.Data.Benchmark/Vitorm.Data.Benchmark.csproj

@@ -15,7 +15,7 @@
       <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.32" />
       <PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.5" />
  
-      <PackageReference Include="SqlSugarCore" Version="5.1.4.162" />
+      <PackageReference Include="SqlSugarCore" Version="5.1.4.166" />
     </ItemGroup>
 
     <ItemGroup>

+ 1 - 3
test/Vitorm.Data.MsTest/CommonTest/ClickHouse_Test.cs

@@ -1,7 +1,5 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-using Vitorm.Sql;
-
 using User = Vitorm.MsTest.ClickHouse.User;
 
 namespace Vitorm.MsTest.ClickHouse
@@ -43,7 +41,7 @@ namespace Vitorm.MsTest
 
         public void Init()
         {
-            using var dbContext = Data.DataProvider<User>()?.CreateDbContext() as SqlDbContext;
+            using var dbContext = Data.DataProvider<User>()?.CreateDbContext();
 
             dbContext.TryDropTable<User>();
             dbContext.TryCreateTable<User>();

+ 1 - 3
test/Vitorm.Data.MsTest/CommonTest/MySql_Test.cs

@@ -1,7 +1,5 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-using Vitorm.Sql;
-
 using User = Vitorm.MsTest.MySql.User;
 
 namespace Vitorm.MsTest.MySql
@@ -47,7 +45,7 @@ namespace Vitorm.MsTest
 
         public void Init()
         {
-            using var dbContext = Data.DataProvider<User>()?.CreateDbContext() as SqlDbContext;
+            using var dbContext = Data.DataProvider<User>()?.CreateDbContext();
 
 
             dbContext.TryDropTable<User>();

+ 1 - 3
test/Vitorm.Data.MsTest/CommonTest/SqlServer_Test.cs

@@ -1,7 +1,5 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-using Vitorm.Sql;
-
 using User = Vitorm.MsTest.SqlServer.User;
 
 namespace Vitorm.MsTest.SqlServer
@@ -46,7 +44,7 @@ namespace Vitorm.MsTest
 
         public void Init()
         {
-            using var dbContext = Data.DataProvider<User>()?.CreateDbContext() as SqlDbContext;
+            using var dbContext = Data.DataProvider<User>()?.CreateDbContext();
 
             dbContext.TryDropTable<User>();
             dbContext.TryCreateTable<User>();

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

@@ -11,13 +11,13 @@
 
     <ItemGroup>
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
-        <PackageReference Include="MSTest.TestAdapter" Version="3.4.3" />
-        <PackageReference Include="MSTest.TestFramework" Version="3.4.3" />
+        <PackageReference Include="MSTest.TestAdapter" Version="3.5.0" />
+        <PackageReference Include="MSTest.TestFramework" Version="3.5.0" />
 
         <PackageReference Include="Vit.Core" Version="2.2.0" />
 
-        <PackageReference Include="Vitorm.ClickHouse" Version="2.0.1" />
-        <PackageReference Include="Vitorm.ElasticSearch"  Version="2.0.1"/>
+        <PackageReference Include="Vitorm.ClickHouse" Version="2.0.2" />
+        <PackageReference Include="Vitorm.ElasticSearch" Version="2.0.2" />
     </ItemGroup>
 
     <ItemGroup>

+ 78 - 0
test/Vitorm.EntityGenerate.MsTest/BaseTest.cs

@@ -0,0 +1,78 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Vit.Core.Module.Serialization;
+using Vit.Linq;
+using Vit.Linq.Filter.ComponentModel;
+
+namespace Vitorm.MsTest
+{
+    public class BaseTest
+    {
+        public static void TestDbSet(IDbSet dbSet)
+        {
+            // #1 Create :  Add AddRange
+            dbSet.Add(new { id = 2, name = "u246" });
+            dbSet.AddRange(new[]{
+                new {id=3,name="u356" },
+                new {id=4,name="u400" },
+                new {id=5,name="u500" },
+                new {id=6,name="u600" }
+            });
+
+
+            // #2 Retrieve : Get Query
+            #region Get
+            {
+                dynamic user = dbSet.Get(2);
+                string name = user.name;
+                Assert.AreEqual("u246", name);
+            }
+            #endregion
+            #region Query
+            {
+                var query = dbSet.Query();
+
+                var strFilter = "{'field':'id',  'operator': '=',  'value': 3 }".Replace("'", "\"");
+                var filter = Json.Deserialize<FilterRule>(strFilter);
+                var users = query.IQueryable_Where(filter).IQueryable_ToList();
+                dynamic user = users[0];
+
+                string name = user.name;
+                Assert.AreEqual("u356", name);
+            }
+            #endregion
+
+            #region #3 Update: Update UpdateRange
+            {
+                dbSet.Update(new { id = 2, name = "u246_" });
+                dbSet.UpdateRange(new[]{
+                    new {id=3,name="u356_" },
+                    new {id=4,name="u400_" }
+                });
+
+                dynamic user = dbSet.Get(2);
+                Assert.AreEqual("u246_", (string)user.name);
+            }
+            #endregion
+
+            #region #4 Delete : Delete DeleteRange DeleteByKey DeleteByKeys
+            {
+                dbSet.Delete(new { id = 2, name = "u246_" });
+                dbSet.DeleteRange(new[]{
+                    new {id=3,name="u356_" },
+                    new {id=4,name="u400_" }
+                });
+
+                dbSet.DeleteByKey(1);
+                dbSet.DeleteByKeys(new[] { 5, 6 });
+
+                var query = dbSet.Query();
+                var count = query.IQueryable_Count();
+                Assert.AreEqual(0, count);
+            }
+            #endregion
+
+        }
+
+    }
+}

+ 41 - 0
test/Vitorm.EntityGenerate.MsTest/SqlServer/EntityGenerate_Data_Test.cs

@@ -0,0 +1,41 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Vitorm.EntityGenerate;
+
+namespace Vitorm.MsTest.SqlServer
+{
+
+    [TestClass]
+    public partial class EntityGenerate_Data_Test
+    {
+
+        [TestMethod]
+        public void Test()
+        {
+            // #1 init
+            var entityNamespace = "Vitorm.MsTest.SqlServer";
+            var dbContext = Data.DataProvider(entityNamespace).CreateSqlDbContext();
+            dbContext.Execute(@"
+if object_id(N'[dev_orm].[GeneratedUser]', N'U') is not null  DROP TABLE [dev_orm].[GeneratedUser];
+CREATE TABLE [dev_orm].[GeneratedUser] ([id] int NOT NULL PRIMARY KEY, [name] varchar(1000) );
+Insert into [dev_orm].[GeneratedUser] ([id],[name]) values(1,'u146');
+");
+
+            // #2 test
+            var dbSet = DataEntity.GenerateDbSet(entityNamespace: entityNamespace, tableName: "GeneratedUser", schemaName: "dev_orm");
+            var entityType = dbSet.entityDescriptor.entityType;
+
+            // GetEntity
+            dynamic user = dbSet.Get(1);
+            string name = user.name;
+            Assert.AreEqual("u146", name);
+
+            BaseTest.TestDbSet(dbSet);
+
+        }
+
+
+
+
+    }
+}

+ 44 - 0
test/Vitorm.EntityGenerate.MsTest/SqlServer/EntityGenerate_Test.cs

@@ -0,0 +1,44 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Vitorm.Sql;
+
+namespace Vitorm.MsTest.SqlServer
+{
+
+    [TestClass]
+    public partial class EntityGenerate_Test
+    {
+
+        [TestMethod]
+        public void Test()
+        {
+            // #1 init
+            var entityNamespace = "Vitorm.MsTest.SqlServer";
+            var connectionString = Vitorm.Data.DataProvider(entityNamespace).CreateSqlDbContext().dbConnection.ConnectionString;
+            using var dbContext = new SqlDbContext();
+            dbContext.UseSqlServer(connectionString);
+
+            dbContext.Execute(@"
+if object_id(N'[dev_orm].[GeneratedUser]', N'U') is not null  DROP TABLE [dev_orm].[GeneratedUser];
+CREATE TABLE [dev_orm].[GeneratedUser] ([id] int NOT NULL PRIMARY KEY, [name] varchar(1000) );
+Insert into [dev_orm].[GeneratedUser] ([id],[name]) values(1,'u146');
+");
+
+            // #2 test
+            var dbSet = dbContext.GenerateDbSet(entityNamespace: entityNamespace, tableName: "GeneratedUser", schemaName: "dev_orm");
+            var entityType = dbSet.entityDescriptor.entityType;
+
+            // GetEntity
+            dynamic user = dbSet.Get(1);
+            string name = user.name;
+            Assert.AreEqual("u146", name);
+
+            BaseTest.TestDbSet(dbSet);
+        }
+
+
+
+
+
+    }
+}

+ 43 - 0
test/Vitorm.EntityGenerate.MsTest/Sqlite_Test/EntityGenerate_Data_Test.cs

@@ -0,0 +1,43 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Vitorm.EntityGenerate;
+
+
+namespace Vitorm.MsTest.Sqlite
+{
+
+    [TestClass]
+    public partial class EntityGenerate_Data_Test
+    {
+
+        [TestMethod]
+        public void Test()
+        {
+            // #1 init
+            var entityNamespace = "Vitorm.MsTest.Sqlite";
+            var dbContext = Data.DataProvider(entityNamespace).CreateSqlDbContext();
+            dbContext.Execute(@"
+DROP TABLE if exists GeneratedUser;
+CREATE TABLE GeneratedUser(id integer NOT NULL PRIMARY KEY,  name text DEFAULT NULL);
+Insert into GeneratedUser(id,name) values(1,'u146');
+");
+
+            // #2 test
+            var dbSet = DataEntity.GenerateDbSet(entityNamespace: entityNamespace, tableName: "GeneratedUser");
+            var entityType = dbSet.entityDescriptor.entityType;
+
+            // Get Entity
+            dynamic user = dbSet.Get(1);
+            string name = user.name;
+            Assert.AreEqual("u146", name);
+
+            BaseTest.TestDbSet(dbSet);
+
+
+        }
+
+
+
+
+    }
+}

+ 39 - 0
test/Vitorm.EntityGenerate.MsTest/Sqlite_Test/EntityGenerate_Test.cs

@@ -0,0 +1,39 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Vitorm.Sql;
+namespace Vitorm.MsTest.Sqlite
+{
+    [TestClass]
+    public partial class EntityGenerate_Test
+    {
+        [TestMethod]
+        public void Test()
+        {
+            // #1 init
+            var entityNamespace = "Vitorm.MsTest.Sqlite";
+            var guid = Guid.NewGuid().ToString();
+            var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{guid}.sqlite.db");
+            var connectionString = $"data source={filePath}";
+
+            using var dbContext = new SqlDbContext();
+            dbContext.UseSqlite(connectionString);
+
+            dbContext.Execute(@"
+DROP TABLE if exists GeneratedUser;
+CREATE TABLE GeneratedUser(id integer NOT NULL PRIMARY KEY,  name text DEFAULT NULL);
+Insert into GeneratedUser(id,name) values(1,'u146');
+");
+
+            // #2 test
+            var dbSet = dbContext.GenerateDbSet(entityNamespace: entityNamespace, tableName: "GeneratedUser");
+            var entityType = dbSet.entityDescriptor.entityType;
+
+            // GetEntity
+            dynamic user = dbSet.Get(1);
+            string name = user.name;
+            Assert.AreEqual("u146", name);
+
+            BaseTest.TestDbSet(dbSet);
+        }
+    }
+}

+ 33 - 0
test/Vitorm.EntityGenerate.MsTest/Vitorm.EntityGenerate.MsTest.csproj

@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <TargetFramework>net6.0</TargetFramework>
+        <ImplicitUsings>enable</ImplicitUsings>
+
+        <IsPackable>false</IsPackable>
+        <IsTestProject>true</IsTestProject>
+        <RootNamespace>Vitorm.MsTest</RootNamespace>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
+        <PackageReference Include="MSTest.TestAdapter" Version="3.5.0" />
+        <PackageReference Include="MSTest.TestFramework" Version="3.5.0" />
+
+        <PackageReference Include="Vit.Core" Version="2.2.0" />
+    </ItemGroup>
+
+    <ItemGroup>
+        <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.Sqlite\Vitorm.Sqlite.csproj" />
+        <ProjectReference Include="..\..\..\Vitorm\src\Vitorm.SqlServer\Vitorm.SqlServer.csproj" />
+        <ProjectReference Include="..\..\src\Vitorm.EntityGenerate\Vitorm.EntityGenerate.csproj" />
+    </ItemGroup>
+
+
+    <ItemGroup>
+        <None Update="appsettings.json">
+            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+        </None>
+    </ItemGroup>
+
+</Project>

+ 17 - 0
test/Vitorm.EntityGenerate.MsTest/appsettings.json

@@ -0,0 +1,17 @@
+{
+  "Vitorm": {
+    "Data": [
+      {
+        "provider": "Sqlite",
+        "namespace": "Vitorm.MsTest.Sqlite",
+        "connectionString": "data source=sqlite.db;"
+      },
+      {
+        "provider": "SqlServer",
+        "namespace": "Vitorm.MsTest.SqlServer",
+        "connectionString": "Server=localhost;Database=dev-orm;User ID=sa;Password=123456;TrustServerCertificate=true;"
+      }
+
+    ]
+  }
+}

+ 3 - 2
test/Vitorm.MySql.MsTest/Vitorm.MySql.MsTest.csproj

@@ -11,8 +11,8 @@
 
     <ItemGroup>
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
-        <PackageReference Include="MSTest.TestAdapter" Version="3.4.3" />
-        <PackageReference Include="MSTest.TestFramework" Version="3.4.3" />
+        <PackageReference Include="MSTest.TestAdapter" Version="3.5.0" />
+        <PackageReference Include="MSTest.TestFramework" Version="3.5.0" />
 
         <PackageReference Include="Vit.Core" Version="2.2.0" />
     </ItemGroup>
@@ -26,6 +26,7 @@
     <ItemGroup>
         <Compile Include="..\Vitorm.Sqlite.MsTest\CommonTest\*.cs" Link="CommonTest\%(RecursiveDir)%(FileName)%(Extension)" />
         <Compile Include="..\Vitorm.Sqlite.MsTest\ExpressionTreeTest\ExpressionTester.cs" Link="ExpressionTreeTest\ExpressionTester.cs" />
+        <Compile Include="..\Vitorm.Sqlite.MsTest\ExpressionTreeTest\ExpressionTester.Model.cs" Link="ExpressionTreeTest\ExpressionTester.Model.cs" />
     </ItemGroup>
 
     <ItemGroup>

+ 3 - 2
test/Vitorm.SqlServer.MsTest/Vitorm.SqlServer.MsTest.csproj

@@ -11,8 +11,8 @@
 
     <ItemGroup>
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
-        <PackageReference Include="MSTest.TestAdapter" Version="3.4.3" />
-        <PackageReference Include="MSTest.TestFramework" Version="3.4.3" />
+        <PackageReference Include="MSTest.TestAdapter" Version="3.5.0" />
+        <PackageReference Include="MSTest.TestFramework" Version="3.5.0" />
 
         <PackageReference Include="Vit.Core" Version="2.2.0" />
     </ItemGroup>
@@ -30,6 +30,7 @@
     <ItemGroup>
         <Compile Include="..\Vitorm.Sqlite.MsTest\CommonTest\*.cs" Link="CommonTest\%(RecursiveDir)%(FileName)%(Extension)" />
         <Compile Include="..\Vitorm.Sqlite.MsTest\ExpressionTreeTest\ExpressionTester.cs" Link="ExpressionTreeTest\ExpressionTester.cs" />
+        <Compile Include="..\Vitorm.Sqlite.MsTest\ExpressionTreeTest\ExpressionTester.Model.cs" Link="ExpressionTreeTest\ExpressionTester.Model.cs" />
     </ItemGroup>
 
 </Project>

+ 1 - 0
test/Vitorm.Sqlite.MsTest/CommonTest/DbContext_Test.cs

@@ -109,6 +109,7 @@ namespace Vitorm.MsTest.CommonTest
         {
             public void CleanCache() { }
             public IEntityDescriptor LoadDescriptor(Type entityType) => LoadFromType(entityType);
+            public IEntityDescriptor LoadDescriptorWithoutCache(Type entityType) => LoadFromType(entityType);
 
             public static bool GetTableName(Type entityType, out string tableName, out string schema)
             {

+ 1 - 4
test/Vitorm.Sqlite.MsTest/ExpressionTreeTest/ExpressionTester.cs

@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Linq;
+using System.Data;
 using System.Linq.Expressions;
 
 using Microsoft.VisualStudio.TestTools.UnitTesting;

+ 1 - 1
test/Vitorm.Sqlite.MsTest/ExpressionTreeTest/Query_Test.cs

@@ -17,7 +17,7 @@ namespace Vitorm.MsTest.ExpressionTreeTest
 
             dbSet.TryDropTable();
             dbSet.TryCreateTable();
-            dbSet.AddRange(initUsers); 
+            dbSet.AddRange(initUsers);
             DataSource.WaitForUpdate();
 
             var query = dbSet.Query();

+ 2 - 2
test/Vitorm.Sqlite.MsTest/Vitorm.Sqlite.MsTest.csproj

@@ -11,8 +11,8 @@
 
     <ItemGroup>
         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
-        <PackageReference Include="MSTest.TestAdapter" Version="3.4.3" />
-        <PackageReference Include="MSTest.TestFramework" Version="3.4.3" />
+        <PackageReference Include="MSTest.TestAdapter" Version="3.5.0" />
+        <PackageReference Include="MSTest.TestFramework" Version="3.5.0" />
 
         <PackageReference Include="Vit.Core" Version="2.2.0" />
     </ItemGroup>