Lith 8 miesięcy temu
rodzic
commit
fe34eb43ca
30 zmienionych plików z 307 dodań i 200 usunięć
  1. 5 0
      doc/ReleaseLog.md
  2. 1 1
      src/Vitorm.EntityGenerate/Extensions/SqlDbContext_EntityType_Extensions.cs
  3. 2 3
      src/Vitorm/DbContext.cs
  4. 0 72
      src/Vitorm/Entity/DataAnnotations/EntityLoader.cs
  5. 1 1
      src/Vitorm/Entity/EntityDescriptorWithAlias.cs
  6. 48 0
      src/Vitorm/Entity/EntityLoaders.cs
  7. 0 0
      src/Vitorm/Entity/Extensions/IEntityDescriptor_Extensions.Column.cs
  8. 0 1
      src/Vitorm/Entity/Extensions/IEntityDescriptor_Extensions.Table.cs
  9. 11 0
      src/Vitorm/Entity/IEntityLoader.cs
  10. 2 2
      src/Vitorm/Entity/Loader/DataAnnotations/ColumnDescriptor.cs
  11. 1 1
      src/Vitorm/Entity/Loader/DataAnnotations/EntityDescriptor.cs
  12. 111 0
      src/Vitorm/Entity/Loader/DataAnnotations/EntityLoader.cs
  13. 19 0
      src/Vitorm/Entity/Loader/DataAnnotations/StrictEntityLoaderAttribute.cs
  14. 0 50
      src/Vitorm/Entity/Loader/DefaultEntityLoader.cs
  15. 30 0
      src/Vitorm/Entity/Loader/EntityLoader_FromAttribute/EntityLoader.cs
  16. 0 11
      src/Vitorm/Entity/Loader/IEntityLoader.cs
  17. 0 10
      src/Vitorm/Entity/LoaderAttribute/EntityLoaderAttribute.cs
  18. 0 24
      src/Vitorm/Entity/LoaderAttribute/EntityLoaderFromAttribute.cs
  19. 0 0
      test/Vitorm.EntityGenerate.MsTest/Sqlite/EntityGenerate_Data_Test.cs
  20. 0 0
      test/Vitorm.EntityGenerate.MsTest/Sqlite/EntityGenerate_Test.cs
  21. 12 14
      test/Vitorm.Sqlite.MsTest/CommonTest/EntityLoader_CustomLoader_Test.cs
  22. 56 0
      test/Vitorm.Sqlite.MsTest/CommonTest/EntityLoader_Test.cs
  23. 1 1
      test/Vitorm.Sqlite.MsTest/CommonTest/Property_DateTime_Test.cs
  24. 1 1
      test/Vitorm.Sqlite.MsTest/CommonTest/Property_Numric_Caculate_Test.cs
  25. 1 1
      test/Vitorm.Sqlite.MsTest/CommonTest/Property_Numric_Test.cs
  26. 1 1
      test/Vitorm.Sqlite.MsTest/CommonTest/Property_String_Caculate_Test.cs
  27. 1 2
      test/Vitorm.Sqlite.MsTest/CommonTest/Property_String_Like_Test.cs
  28. 1 1
      test/Vitorm.Sqlite.MsTest/CommonTest/Property_String_Test.cs
  29. 1 1
      test/Vitorm.Sqlite.MsTest/CommonTest/Query_FilterRule_Test.cs
  30. 1 2
      test/Vitorm.Sqlite.MsTest/CommonTest/Query_FilterRule_WithJoin_Test.cs

+ 5 - 0
doc/ReleaseLog.md

@@ -16,6 +16,11 @@
   - ExecuteUpdateAsync
   - FirstOrDefaultAsync FirstAsync LastOrDefaultAsync LastAsync
 
+- [Vitorm] EntityLoader_FromAttribute
+- [Vitorm] Vitorm.Entity.Loader.DataAnnotations.EntityLoader (strictMode, default false)
+> strictMode is false: will get typeName as tableName if not specify TableAttribute, and will set property named Id (or tableName + "Id") as key
+
+
 -----------------------
 # 2.0.4
 - [Vitorm] support Truncate

+ 1 - 1
src/Vitorm.EntityGenerate/Extensions/SqlDbContext_EntityType_Extensions.cs

@@ -30,7 +30,7 @@ namespace Vitorm
             }
             else
             {
-                var entityDescriptor = dbContext.entityLoader.LoadDescriptorWithoutCache(entityType);
+                var entityDescriptor = dbContext.entityLoader.LoadDescriptorWithoutCache(entityType).entityDescriptor;
                 dbSet = Vitorm.Sql.DbSetConstructor.CreateDbSet(dbContext, entityDescriptor);
             }
             return dbSet;

+ 2 - 3
src/Vitorm/DbContext.cs

@@ -6,7 +6,6 @@ using Vit.Linq.ExpressionNodes;
 using Vit.Linq.ExpressionNodes.ExpressionConvertor.MethodCalls;
 
 using Vitorm.Entity;
-using Vitorm.Entity.Loader;
 
 namespace Vitorm
 {
@@ -65,13 +64,13 @@ namespace Vitorm
 
         #region EntityLoader
 
-        public static DefaultEntityLoader defaultEntityLoader = new();
+        public static EntityLoaders defaultEntityLoader = new();
 
         public IEntityLoader entityLoader = defaultEntityLoader;
         public virtual IEntityDescriptor GetEntityDescriptor(Type entityType, bool tryFromCache = true)
         {
             if (tryFromCache && dbSetMap?.TryGetValue(entityType, out var dbSet) == true) return dbSet.entityDescriptor;
-            return entityLoader.LoadDescriptor(entityType);
+            return entityLoader.LoadDescriptor(entityType).entityDescriptor;
         }
         public virtual IEntityDescriptor GetEntityDescriptor<Entity>(bool tryFromCache = true)
             => GetEntityDescriptor(typeof(Entity), tryFromCache);

+ 0 - 72
src/Vitorm/Entity/DataAnnotations/EntityLoader.cs

@@ -1,72 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations.Schema;
-using System.Linq;
-using System.Reflection;
-
-using Vitorm.Entity.Loader;
-
-namespace Vitorm.Entity.DataAnnotations
-{
-    public class EntityLoader : IEntityLoader
-    {
-        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)
-        {
-            var attribute = entityType?.GetCustomAttribute<global::System.ComponentModel.DataAnnotations.Schema.TableAttribute>();
-            tableName = attribute?.Name;
-            schema = attribute?.Schema;
-            return attribute != null;
-        }
-
-        public static EntityDescriptor LoadFromType(Type entityType)
-        {
-            if (!GetTableName(entityType, out var tableName, out var schema)) return null;
-
-            IColumnDescriptor[] allColumns = entityType?.GetProperties(BindingFlags.Public | BindingFlags.Instance)
-                .Select(propertyInfo =>
-             {
-                 if (propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute>() != null) return null;
-
-                 // #1 isKey
-                 bool isKey = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.KeyAttribute>() != null;
-
-                 // #2 column name and type
-                 string columnName; string databaseType; int? columnOrder;
-                 var columnAttr = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.ColumnAttribute>();
-                 columnName = columnAttr?.Name ?? propertyInfo.Name;
-                 databaseType = columnAttr?.TypeName;
-                 columnOrder = columnAttr?.Order;
-
-                 // #3 isIdentity
-                 var isIdentity = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute>()?.DatabaseGeneratedOption == DatabaseGeneratedOption.Identity;
-
-                 // #4 isNullable
-                 bool isNullable;
-                 if (propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.RequiredAttribute>() != null) isNullable = false;
-                 else
-                 {
-                     var type = propertyInfo.PropertyType;
-                     if (type == typeof(string)) isNullable = true;
-                     else
-                     {
-                         isNullable = (type.IsGenericType && typeof(Nullable<>) == type.GetGenericTypeDefinition());
-                     }
-                 }
-
-                 return new ColumnDescriptor(propertyInfo, columnName: columnName, isKey: isKey, isIdentity: isIdentity, databaseType: databaseType, isNullable: isNullable, columnOrder: columnOrder);
-             }).Where(column => column != null).ToArray();
-
-            return new EntityDescriptor(entityType, allColumns, tableName, schema);
-        }
-
-
-    }
-}

+ 1 - 1
src/Vitorm/Entity/DataAnnotations/EntityDescriptorWithAlias.cs → src/Vitorm/Entity/EntityDescriptorWithAlias.cs

@@ -1,6 +1,6 @@
 using System;
 
-namespace Vitorm.Entity.DataAnnotations
+namespace Vitorm.Entity
 {
     public partial class EntityDescriptorWithAlias : IEntityDescriptor
     {

+ 48 - 0
src/Vitorm/Entity/EntityLoaders.cs

@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace Vitorm.Entity
+{
+    public class EntityLoaders : IEntityLoader
+    {
+        public List<IEntityLoader> loaders = new();
+        public EntityLoaders()
+        {
+            loaders.Add(new Loader.EntityLoader_FromAttribute.EntityLoader());
+
+            loaders.Add(new Loader.DataAnnotations.EntityLoader());
+        }
+
+        readonly ConcurrentDictionary<Type, IEntityDescriptor> descriptorCache = new();
+
+        public void CleanCache()
+        {
+            descriptorCache.Clear();
+            foreach (var loader in loaders) loader.CleanCache();
+        }
+
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptor(Type entityType)
+        {
+            if (descriptorCache.TryGetValue(entityType, out var entityDescriptor))
+                return (true, entityDescriptor);
+
+            var result = LoadDescriptorWithoutCache(entityType);
+            if (result.success)
+                descriptorCache[entityType] = result.entityDescriptor;
+
+            return result;
+        }
+
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptorWithoutCache(Type entityType)
+        {
+            foreach (var loader in loaders)
+            {
+                var result = loader.LoadDescriptor(entityType);
+                if (result.success) return result;
+            }
+            return default;
+        }
+
+    }
+}

+ 0 - 0
src/Vitorm/Entity/IEntityDescriptor_Extensions.cs → src/Vitorm/Entity/Extensions/IEntityDescriptor_Extensions.Column.cs


+ 0 - 1
src/Vitorm/Extensions/IEntityDescriptor_Extensions.cs → src/Vitorm/Entity/Extensions/IEntityDescriptor_Extensions.Table.cs

@@ -1,5 +1,4 @@
 using Vitorm.Entity;
-using Vitorm.Entity.DataAnnotations;
 
 namespace Vitorm
 {

+ 11 - 0
src/Vitorm/Entity/IEntityLoader.cs

@@ -0,0 +1,11 @@
+using System;
+
+namespace Vitorm.Entity
+{
+    public interface IEntityLoader
+    {
+        void CleanCache();
+        (bool success, IEntityDescriptor entityDescriptor) LoadDescriptor(Type entityType);
+        (bool success, IEntityDescriptor entityDescriptor) LoadDescriptorWithoutCache(Type entityType);
+    }
+}

+ 2 - 2
src/Vitorm/Entity/DataAnnotations/ColumnDescriptor.cs → src/Vitorm/Entity/Loader/DataAnnotations/ColumnDescriptor.cs

@@ -1,7 +1,7 @@
 using System;
 using System.Reflection;
 
-namespace Vitorm.Entity.DataAnnotations
+namespace Vitorm.Entity.Loader.DataAnnotations
 {
     public class ColumnDescriptor : IColumnDescriptor
     {
@@ -32,7 +32,7 @@ namespace Vitorm.Entity.DataAnnotations
         /// </summary>
         public string columnName { get; private set; }
 
-        public bool isKey { get; private set; }
+        public bool isKey { get; set; }
 
         /// <summary>
         /// whether column is Identity

+ 1 - 1
src/Vitorm/Entity/DataAnnotations/EntityDescriptor.cs → src/Vitorm/Entity/Loader/DataAnnotations/EntityDescriptor.cs

@@ -1,7 +1,7 @@
 using System;
 using System.Linq;
 
-namespace Vitorm.Entity.DataAnnotations
+namespace Vitorm.Entity.Loader.DataAnnotations
 {
     public partial class EntityDescriptor : IEntityDescriptor
     {

+ 111 - 0
src/Vitorm/Entity/Loader/DataAnnotations/EntityLoader.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Reflection;
+
+namespace Vitorm.Entity.Loader.DataAnnotations
+{
+    public class EntityLoader : IEntityLoader
+    {
+        /// <summary>
+        /// if strictMode is false: will get typeName as tableName if not specify TableAttribute, and will set property named Id (or tableName + "Id") as key
+        /// </summary>
+        public static bool strictMode { get; set; } = false;
+
+        public void CleanCache()
+        {
+        }
+
+        /// <summary>
+        /// if strictMode is false: will get typeName as tableName if not specify TableAttribute, and will set property named Id (or tableName + "Id") as key
+        /// </summary>
+        public bool? StrictMode { get; set; }
+
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptor(Type entityType) => LoadDescriptorWithoutCache(entityType);
+
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptorWithoutCache(Type entityType) => LoadFromType(entityType, strictMode: StrictMode ?? strictMode);
+
+
+        public static (string tableName, string schema) GetTableName(Type entityType)
+        {
+            var attribute = entityType?.GetCustomAttribute<global::System.ComponentModel.DataAnnotations.Schema.TableAttribute>();
+            var tableName = attribute?.Name;
+            var schema = attribute?.Schema;
+            return (tableName, schema);
+        }
+
+
+        /// <summary>
+        /// if strictMode is false: will get typeName as tableName if not specify TableAttribute, and will set property named Id (or tableName + "Id") as key
+        /// </summary>
+        /// <param name="entityType"></param>
+        /// <param name="strictMode"></param>
+        /// <returns></returns>
+        public static (bool success, EntityDescriptor entityDescriptor) LoadFromType(Type entityType, bool strictMode = false)
+        {
+            (string tableName, string schema) = GetTableName(entityType);
+
+            if (string.IsNullOrEmpty(tableName))
+            {
+                if (strictMode) return (true, null);
+                tableName = entityType.Name;
+            }
+
+            var columns = LoadColumns(entityType);
+
+            // key
+            if (!strictMode && !columns.Any(col => col.isKey))
+            {
+                var keyNames = new[] { "id", tableName + "id" };
+                var keyColumn = columns.FirstOrDefault(col => keyNames.Contains(col.columnName, StringComparer.OrdinalIgnoreCase));
+                if (keyColumn != null) keyColumn.isKey = true;
+            }
+
+            IColumnDescriptor[] allColumns = columns.Select(m => (IColumnDescriptor)m).ToArray();
+
+            return (true, new EntityDescriptor(entityType, allColumns, tableName, schema));
+        }
+
+
+        public static List<ColumnDescriptor> LoadColumns(Type entityType)
+        {
+            return entityType?.GetProperties(BindingFlags.Public | BindingFlags.Instance)
+                .Select(propertyInfo =>
+                {
+                    if (propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute>() != null) return null;
+
+                    // #1 isKey
+                    bool isKey = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.KeyAttribute>() != null;
+
+                    // #2 column name and type
+                    string columnName; string databaseType; int? columnOrder;
+                    var columnAttr = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.ColumnAttribute>();
+                    columnName = columnAttr?.Name ?? propertyInfo.Name;
+                    databaseType = columnAttr?.TypeName;
+                    columnOrder = columnAttr?.Order;
+
+                    // #3 isIdentity
+                    var isIdentity = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute>()?.DatabaseGeneratedOption == DatabaseGeneratedOption.Identity;
+
+                    // #4 isNullable
+                    bool isNullable;
+                    if (propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.RequiredAttribute>() != null) isNullable = false;
+                    else
+                    {
+                        var type = propertyInfo.PropertyType;
+                        if (type == typeof(string)) isNullable = true;
+                        else
+                        {
+                            isNullable = (type.IsGenericType && typeof(Nullable<>) == type.GetGenericTypeDefinition());
+                        }
+                    }
+
+                    return new ColumnDescriptor(propertyInfo, columnName: columnName, isKey: isKey, isIdentity: isIdentity, databaseType: databaseType, isNullable: isNullable, columnOrder: columnOrder);
+                }).Where(column => column != null).ToList();
+        }
+
+
+
+    }
+}

+ 19 - 0
src/Vitorm/Entity/Loader/DataAnnotations/StrictEntityLoaderAttribute.cs

@@ -0,0 +1,19 @@
+using System;
+
+namespace Vitorm.Entity.Loader.DataAnnotations
+{
+    /// <summary>
+    /// strictMode to load EntityDescriptor: must specify TableAttribute , if not specify KeyAttribute will not have key column
+    /// </summary>
+    public class StrictEntityLoaderAttribute : Attribute, IEntityLoader
+    {
+        public void CleanCache()
+        {
+        }
+
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptor(Type entityType) => LoadDescriptorWithoutCache(entityType);
+
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptorWithoutCache(Type entityType) => EntityLoader.LoadFromType(entityType, strictMode: true);
+
+    }
+}

+ 0 - 50
src/Vitorm/Entity/Loader/DefaultEntityLoader.cs

@@ -1,50 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-
-using Vitorm.Entity.LoaderAttribute;
-
-namespace Vitorm.Entity.Loader
-{
-    public class DefaultEntityLoader : IEntityLoader
-    {
-        public List<IEntityLoader> loaders = new();
-        public DefaultEntityLoader()
-        {
-            loaders.Add(new DataAnnotations.EntityLoader());
-
-            loaders.Add(new EntityLoaderFromAttribute());
-        }
-
-        readonly ConcurrentDictionary<Type, IEntityDescriptor> descriptorCache = new();
-
-        public void CleanCache()
-        {
-            descriptorCache.Clear();
-            foreach (var loader in loaders) loader.CleanCache();
-        }
-
-        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)
-            {
-                var entityDescriptor = loader.LoadDescriptor(entityType);
-                if (entityDescriptor != null)
-                {
-                    return entityDescriptor;
-                }
-            }
-            return null;
-        }
-
-    }
-}

+ 30 - 0
src/Vitorm/Entity/Loader/EntityLoader_FromAttribute/EntityLoader.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Linq;
+
+namespace Vitorm.Entity.Loader.EntityLoader_FromAttribute
+{
+    /// <summary>
+    /// EntityLoader_FromAttribute
+    /// </summary>
+    public class EntityLoader : IEntityLoader
+    {
+        public static IEntityLoader GetEntityLoader(Type entityType)
+        {
+            var attr = entityType.GetCustomAttributes(true).FirstOrDefault(attr => attr is IEntityLoader);
+            return attr as IEntityLoader;
+        }
+
+        public void CleanCache()
+        {
+        }
+
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptor(Type entityType) => LoadDescriptorWithoutCache(entityType);
+        public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptorWithoutCache(Type entityType)
+        {
+            var entityLoader = GetEntityLoader(entityType);
+            if (entityLoader == null) return default;
+            return entityLoader.LoadDescriptor(entityType);
+        }
+
+    }
+}

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

@@ -1,11 +0,0 @@
-using System;
-
-namespace Vitorm.Entity.Loader
-{
-    public interface IEntityLoader
-    {
-        void CleanCache();
-        IEntityDescriptor LoadDescriptor(Type entityType);
-        IEntityDescriptor LoadDescriptorWithoutCache(Type entityType);
-    }
-}

+ 0 - 10
src/Vitorm/Entity/LoaderAttribute/EntityLoaderAttribute.cs

@@ -1,10 +0,0 @@
-using System;
-
-namespace Vitorm.Entity.LoaderAttribute
-{
-    [AttributeUsage(AttributeTargets.Class)]
-    public class EntityLoaderAttribute : Attribute
-    {
-        public Type Loader { get; set; }
-    }
-}

+ 0 - 24
src/Vitorm/Entity/LoaderAttribute/EntityLoaderFromAttribute.cs

@@ -1,24 +0,0 @@
-using System;
-using System.Reflection;
-
-using Vitorm.Entity.Loader;
-
-namespace Vitorm.Entity.LoaderAttribute
-{
-    public class EntityLoaderFromAttribute : IEntityLoader
-    {
-        public void CleanCache()
-        {
-        }
-
-        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;
-            var loader = Activator.CreateInstance(loaderType) as IEntityLoader;
-            return loader?.LoadDescriptor(entityType);
-        }
-    }
-}

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


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


+ 12 - 14
test/Vitorm.Sqlite.MsTest/CommonTest/DbContext_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/EntityLoader_CustomLoader_Test.cs

@@ -3,17 +3,15 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 
 using Vitorm.Entity;
-using Vitorm.Entity.DataAnnotations;
-using Vitorm.Entity.Loader;
-using Vitorm.Entity.LoaderAttribute;
+using Vitorm.Entity.Loader.DataAnnotations;
 
 namespace Vitorm.MsTest.CommonTest
 {
     [TestClass]
-    public class DbContext_Test
+    public class EntityLoader_CustomLoador_Test
     {
         [TestMethod]
-        public void EntityDescriptor_Test()
+        public void Test_EntityDescriptor()
         {
             using var dbContext = DataSource.CreateDbContext();
             var entityDescriptor = dbContext.GetEntityDescriptor(typeof(User));
@@ -24,7 +22,7 @@ namespace Vitorm.MsTest.CommonTest
 
 
         [TestMethod]
-        public void EntityLoader_Test()
+        public void Test_EntityLoader()
         {
             using var dbContext = DataSource.CreateDbContext();
 
@@ -38,7 +36,7 @@ namespace Vitorm.MsTest.CommonTest
 
             // #2 defaultEntityLoader
             {
-                DbContext.defaultEntityLoader.loaders.Insert(0, new CustomEntityLoader());
+                DbContext.defaultEntityLoader.loaders.Insert(0, new CustomEntityLoaderAttribute());
 
                 var users = dbContext.Query<CustomUser>().Where(m => m.name == "u146").ToList();
                 Assert.AreEqual(1, users.Count());
@@ -50,7 +48,7 @@ namespace Vitorm.MsTest.CommonTest
 
         #region Custom Entity
 
-        [EntityLoader(Loader = typeof(CustomEntityLoader))]
+        [CustomEntityLoader]
         public class CustomUser2 : CustomUser
         {
         }
@@ -105,11 +103,11 @@ namespace Vitorm.MsTest.CommonTest
         #endregion
 
         #region Custom EntityLoader
-        public class CustomEntityLoader : IEntityLoader
+        public class CustomEntityLoaderAttribute : Attribute, IEntityLoader
         {
             public void CleanCache() { }
-            public IEntityDescriptor LoadDescriptor(Type entityType) => LoadFromType(entityType);
-            public IEntityDescriptor LoadDescriptorWithoutCache(Type entityType) => LoadFromType(entityType);
+            public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptor(Type entityType) => LoadFromType(entityType);
+            public (bool success, IEntityDescriptor entityDescriptor) LoadDescriptorWithoutCache(Type entityType) => LoadFromType(entityType);
 
             public static bool GetTableName(Type entityType, out string tableName, out string schema)
             {
@@ -119,9 +117,9 @@ namespace Vitorm.MsTest.CommonTest
                 return tableName != null;
             }
 
-            public static EntityDescriptor LoadFromType(Type entityType)
+            public static (bool success, IEntityDescriptor EntityDescriptor) LoadFromType(Type entityType)
             {
-                if (!GetTableName(entityType, out var tableName, out var schema)) return null;
+                if (!GetTableName(entityType, out var tableName, out var schema)) return default;
 
                 IColumnDescriptor[] allColumns = entityType?.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                     .Select(propertyInfo =>
@@ -158,7 +156,7 @@ namespace Vitorm.MsTest.CommonTest
                         return new ColumnDescriptor(propertyInfo, columnName: columnName, isKey: isKey, isIdentity: isIdentity, databaseType: databaseType, isNullable: isNullable, columnOrder: columnOrder);
                     }).Where(column => column != null).ToArray();
 
-                return new EntityDescriptor(entityType, allColumns, tableName, schema);
+                return (true, new EntityDescriptor(entityType, allColumns, tableName, schema));
             }
         }
         #endregion

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

@@ -0,0 +1,56 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Vitorm.MsTest.CommonTest
+{
+    [TestClass]
+    public class EntityLoader_Test
+    {
+        [TestMethod]
+        public void Test_EntityDescriptor()
+        {
+            using var dbContext = DataSource.CreateDbContext();
+
+            {
+                var entityDescriptor = dbContext.GetEntityDescriptor<User>();
+                Assert.AreEqual("id", entityDescriptor.key?.columnName);
+                Assert.AreEqual("User", entityDescriptor.tableName);
+            }
+
+            {
+                var entityDescriptor = dbContext.GetEntityDescriptor<User2>();
+                Assert.IsNull(entityDescriptor.key);
+                Assert.AreEqual("User", entityDescriptor.tableName);
+            }
+
+            {
+                var entityDescriptor = dbContext.GetEntityDescriptor<User3>();
+                Assert.IsNull(entityDescriptor);
+            }
+        }
+
+
+        #region Custom Entity
+
+        public class User
+        {
+            public int id { get; set; }
+            public string name { get; set; }
+        }
+
+        [Vitorm.Entity.Loader.DataAnnotations.StrictEntityLoader]
+        [Table("User")]
+        public class User2 : User { }
+
+
+        [Vitorm.Entity.Loader.DataAnnotations.StrictEntityLoader]
+        public class User3 : User { }
+
+        #endregion
+
+
+
+
+    }
+}

+ 1 - 1
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Type_DateTime_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Property_DateTime_Test.cs

@@ -6,7 +6,7 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Type_DateTime_Test
+    public class Property_DateTime_Test
     {
 
         [TestMethod]

+ 1 - 1
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Type_Numric_Caculate_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Property_Numric_Caculate_Test.cs

@@ -6,7 +6,7 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Type_Numric_Caculate_Test
+    public class Property_Numric_Caculate_Test
     {
 
         [TestMethod]

+ 1 - 1
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Type_Numric_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Property_Numric_Test.cs

@@ -6,7 +6,7 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Type_Numeric_Test
+    public class Property_Numeric_Test
     {
         // Enumerable.Contains
         // Queryable.Contains

+ 1 - 1
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Type_String_Caculate_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Property_String_Caculate_Test.cs

@@ -6,7 +6,7 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Type_String_Caculate_Test
+    public class Property_String_Caculate_Test
     {
 
 

+ 1 - 2
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Type_String_Like_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Property_String_Like_Test.cs

@@ -6,10 +6,9 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Type_String_Like_Test
+    public class Property_String_Like_Test
     {
 
-
         [TestMethod]
         public void Test_Like()
         {

+ 1 - 1
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Type_String_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Property_String_Test.cs

@@ -6,7 +6,7 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Type_String_Test
+    public class Property_String_Test
     {
 
         // Enumerable.Contains

+ 1 - 1
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Filter_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Query_FilterRule_Test.cs

@@ -9,7 +9,7 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Filter_Test
+    public class Query_FilterRule_Test
     {
 
         [TestMethod]

+ 1 - 2
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Filter_WithJoin_Test.cs → test/Vitorm.Sqlite.MsTest/CommonTest/Query_FilterRule_WithJoin_Test.cs

@@ -8,10 +8,9 @@ namespace Vitorm.MsTest.CommonTest
 {
 
     [TestClass]
-    public class Query_Filter_WithJoin_Test
+    public class Query_FilterRule_WithJoin_Test
     {
 
-
         [TestMethod]
         public void Test()
         {