Procházet zdrojové kódy

fix the issue when column name from database differ from property name from entity

Lith před 10 měsíci
rodič
revize
39a9e23d85
25 změnil soubory, kde provedl 301 přidání a 75 odebrání
  1. 1 1
      src/Vitorm.MySql/SqlTranslateService.cs
  2. 7 1
      src/Vitorm.MySql/TranslateService/ExecuteUpdateTranslateService.cs
  3. 8 2
      src/Vitorm.SqlServer/SqlTranslate/ExecuteUpdateTranslateService.cs
  4. 1 1
      src/Vitorm.SqlServer/SqlTranslateService.cs
  5. 1 1
      src/Vitorm.Sqlite/SqlTranslateService.cs
  6. 10 4
      src/Vitorm.Sqlite/TranslateService/ExecuteUpdateTranslateService.cs
  7. 10 4
      src/Vitorm/Entity/DataAnnotations/ColumnDescriptor.cs
  8. 1 1
      src/Vitorm/Entity/DataAnnotations/EntityDescriptor.cs
  9. 3 3
      src/Vitorm/Entity/DataAnnotations/EntityLoader.cs
  10. 20 0
      src/Vitorm/Entity/Extensions/IEntityDescriptor_Extensions.cs
  11. 8 1
      src/Vitorm/Entity/IColumnDescriptor.cs
  12. 1 1
      src/Vitorm/Sql/DataReader/EntityReader/ModelReader.cs
  13. 1 1
      src/Vitorm/Sql/SqlDbContext.cs
  14. 31 9
      src/Vitorm/Sql/SqlTranslate/SqlTranslateService.cs
  15. 2 2
      src/Vitorm/StreamQuery/StreamReader.cs
  16. 31 0
      src/Vitorm/TypeUtil.cs
  17. 48 9
      test/Vitorm.MySql.MsTest/DataSource.cs
  18. 48 13
      test/Vitorm.SqlServer.MsTest/DataSource.cs
  19. 11 4
      test/Vitorm.Sqlite.MsTest/CommonTest/DbContext_Test.cs
  20. 2 2
      test/Vitorm.Sqlite.MsTest/CommonTest/Query_Group_Test.cs
  21. 2 2
      test/Vitorm.Sqlite.MsTest/CommonTest/Query_InnerJoin_ByJoin_Test.cs
  22. 2 2
      test/Vitorm.Sqlite.MsTest/CommonTest/Query_InnerJoin_BySelectMany_Test.cs
  23. 2 2
      test/Vitorm.Sqlite.MsTest/CommonTest/Query_LeftJoin_ByGroupJoin_Test.cs
  24. 6 3
      test/Vitorm.Sqlite.MsTest/CommonTest/Query_LeftJoin_BySelectMany_Test.cs
  25. 44 6
      test/Vitorm.Sqlite.MsTest/DataSource.cs

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

@@ -188,7 +188,7 @@ CREATE TABLE {DelimitTableName(entityDescriptor)} (
             {
                 var columnDbType = column.databaseType ?? GetColumnDbType(column.type);
                 // name varchar(100) DEFAULT NULL
-                return $"  {DelimitIdentifier(column.name)} {columnDbType} {(column.isNullable ? "DEFAULT NULL" : "NOT NULL")}";
+                return $"  {DelimitIdentifier(column.columnName)} {columnDbType} {(column.isNullable ? "DEFAULT NULL" : "NOT NULL")}";
             }
         }
         protected override string GetColumnDbType(Type type)

+ 7 - 1
src/Vitorm.MySql/TranslateService/ExecuteUpdateTranslateService.cs

@@ -2,6 +2,8 @@
 using System.Collections.Generic;
 using System.Linq;
 
+using Vit.Extensions.Vitorm_Extensions;
+
 using Vitorm.Sql.SqlTranslate;
 using Vitorm.StreamQuery;
 
@@ -42,7 +44,11 @@ where t0.id = tmp.id ;
 
             var sqlToUpdateCols = columnsToUpdate
                 .Select(m => m.name)
-                .Select(name => $"{NewLine}  {sqlTranslator.GetSqlField("t0", name)} = {sqlTranslator.GetSqlField("tmp", name)} ");
+                .Select(name =>
+                {
+                    var columnName = entityDescriptor.GetColumnNameByPropertyName(name);
+                    return $"{NewLine}  {sqlTranslator.GetSqlField("t0", columnName)} = {sqlTranslator.GetSqlField("tmp", name)} ";
+                });
 
             sql += string.Join(",", sqlToUpdateCols);
 

+ 8 - 2
src/Vitorm.SqlServer/SqlTranslate/ExecuteUpdateTranslateService.cs

@@ -2,6 +2,8 @@
 using System.Collections.Generic;
 using System.Linq;
 
+using Vit.Extensions.Vitorm_Extensions;
+
 using Vitorm.Sql.SqlTranslate;
 using Vitorm.StreamQuery;
 
@@ -44,7 +46,11 @@ UPDATE [User]
 
             var sqlToUpdateCols = columnsToUpdate
                 .Select(m => m.name)
-                .Select(name => $"{NewLine}  {sqlTranslator.DelimitIdentifier(name)} = {sqlTranslator.GetSqlField("tmp", name)} ");
+                .Select(name =>
+                {
+                    var columnName = entityDescriptor.GetColumnNameByPropertyName(name);
+                    return $"{NewLine}  {sqlTranslator.DelimitIdentifier(columnName)} = {sqlTranslator.GetSqlField("tmp", name)} ";
+                });
 
             sql += string.Join(",", sqlToUpdateCols);
 
@@ -62,7 +68,7 @@ UPDATE [User]
         protected override string ReadSelect(QueryTranslateArgument arg, CombinedStream stream, string prefix = "select")
         {
             var entityDescriptor = arg.dbContext.GetEntityDescriptor(arg.resultEntityType);
-            var columnsToUpdate = (stream as StreamToUpdate) ?.fieldsToUpdate?.memberArgs;
+            var columnsToUpdate = (stream as StreamToUpdate)?.fieldsToUpdate?.memberArgs;
 
             if (columnsToUpdate?.Any() != true) throw new ArgumentException("can not get columns to update");
 

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

@@ -199,7 +199,7 @@ CREATE TABLE {DelimitTableName(entityDescriptor)} (
             {
                 var columnDbType = column.databaseType ?? GetColumnDbType(column.type);
                 // name varchar(100) DEFAULT NULL
-                return $"  {DelimitIdentifier(column.name)} {columnDbType} {(column.isNullable ? "DEFAULT NULL" : "NOT NULL")}";
+                return $"  {DelimitIdentifier(column.columnName)} {columnDbType} {(column.isNullable ? "DEFAULT NULL" : "NOT NULL")}";
             }
         }
 

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

@@ -169,7 +169,7 @@ CREATE TABLE {DelimitTableName(entityDescriptor)} (
             {
                 var columnDbType = column.databaseType ?? GetColumnDbType(column.type);
                 // name varchar(100) DEFAULT NULL
-                return $"  {DelimitIdentifier(column.name)} {columnDbType} {(column.isNullable ? "DEFAULT NULL" : "NOT NULL")}";
+                return $"  {DelimitIdentifier(column.columnName)} {columnDbType} {(column.isNullable ? "DEFAULT NULL" : "NOT NULL")}";
             }
         }
         protected override string GetColumnDbType(Type type)

+ 10 - 4
src/Vitorm.Sqlite/TranslateService/ExecuteUpdateTranslateService.cs

@@ -2,6 +2,8 @@
 using System.Collections.Generic;
 using System.Linq;
 
+using Vit.Extensions.Vitorm_Extensions;
+
 using Vitorm.Sql.SqlTranslate;
 using Vitorm.StreamQuery;
 
@@ -47,7 +49,11 @@ UPDATE User SET name = 'u'||id  where id > 0;
 
             var sqlToUpdateCols = columnsToUpdate
                 .Select(m => m.name)
-                .Select(name => $"{NewLine}  {sqlTranslator.DelimitIdentifier(name)} = (SELECT {sqlTranslator.DelimitIdentifier("_" + name)} FROM tmp WHERE tmp.{sqlTranslator.DelimitIdentifier(keyName)} = {sqlTranslator.DelimitTableName(entityDescriptor)}.{sqlTranslator.DelimitIdentifier(keyName)} )");
+                .Select(name =>
+                {
+                    var columnName = entityDescriptor.GetColumnNameByPropertyName(name);
+                    return $"{NewLine}  {sqlTranslator.DelimitIdentifier(columnName)} = (SELECT {sqlTranslator.DelimitIdentifier("_" + name)} FROM tmp WHERE tmp.{sqlTranslator.DelimitIdentifier(keyName)} = {sqlTranslator.DelimitTableName(entityDescriptor)}.{sqlTranslator.DelimitIdentifier(keyName)} )";
+                });
 
             sql += string.Join(",", sqlToUpdateCols);
 
@@ -55,7 +61,7 @@ UPDATE User SET name = 'u'||id  where id > 0;
 
             return sql;
         }
- 
+
 
         public ExecuteUpdateTranslateService(SqlTranslateService sqlTranslator) : base(sqlTranslator)
         {
@@ -64,7 +70,7 @@ UPDATE User SET name = 'u'||id  where id > 0;
         protected override string ReadSelect(QueryTranslateArgument arg, CombinedStream stream, string prefix = "select")
         {
             var entityDescriptor = arg.dbContext.GetEntityDescriptor(arg.resultEntityType);
-            var columnsToUpdate = (stream as StreamToUpdate) ?.fieldsToUpdate?.memberArgs;
+            var columnsToUpdate = (stream as StreamToUpdate)?.fieldsToUpdate?.memberArgs;
 
             if (columnsToUpdate?.Any() != true) throw new ArgumentException("can not get columns to update");
 
@@ -72,7 +78,7 @@ UPDATE User SET name = 'u'||id  where id > 0;
 
             foreach (var column in columnsToUpdate)
             {
-                sqlFields.Add($"({sqlTranslator.EvalExpression( arg,  column.value)}) as {sqlTranslator.DelimitIdentifier("_" + column.name)}");
+                sqlFields.Add($"({sqlTranslator.EvalExpression(arg, column.value)}) as {sqlTranslator.DelimitIdentifier("_" + column.name)}");
             }
 
             // primary key

+ 10 - 4
src/Vitorm/Entity/DataAnnotations/ColumnDescriptor.cs

@@ -5,12 +5,12 @@ namespace Vitorm.Entity.DataAnnotations
 {
     public class ColumnDescriptor : IColumnDescriptor
     {
-        public ColumnDescriptor(PropertyInfo propertyInfo, string name, bool isKey, bool isIdentity, string databaseType, bool isNullable, int? columnOrder = null, bool? isIndex = null)
+        public ColumnDescriptor(PropertyInfo propertyInfo, string columnName, bool isKey, bool isIdentity, string databaseType, bool isNullable, int? columnOrder = null, bool? isIndex = null)
         {
             this.propertyInfo = propertyInfo;
             type = propertyInfo.PropertyType;
 
-            this.name = name;
+            this.columnName = columnName;
             this.isKey = isKey;
             this.isIdentity = isIdentity;
             this.databaseType = databaseType;
@@ -23,8 +23,14 @@ namespace Vitorm.Entity.DataAnnotations
         PropertyInfo propertyInfo;
         public Type type { get; private set; }
 
-
-        public string name { get; private set; }
+        /// <summary>
+        /// property name in Entity Type
+        /// </summary>
+        public string propertyName => propertyInfo?.Name;
+        /// <summary>
+        /// column name in database
+        /// </summary>
+        public string columnName { get; private set; }
 
         public bool isKey { get; private set; }
 

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

@@ -24,7 +24,7 @@ namespace Vitorm.Entity.DataAnnotations
         /// <summary>
         /// primary key name
         /// </summary>
-        public string keyName => key?.name;
+        public string keyName => key?.columnName;
 
         /// <summary>
         /// primary key

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

@@ -39,9 +39,9 @@ namespace Vitorm.Entity.DataAnnotations
                  bool isKey = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.KeyAttribute>() != null;
 
                  // #2 column name and type
-                 string name; string databaseType; int? columnOrder;
+                 string columnName; string databaseType; int? columnOrder;
                  var columnAttr = propertyInfo.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.ColumnAttribute>();
-                 name = columnAttr?.Name ?? propertyInfo.Name;
+                 columnName = columnAttr?.Name ?? propertyInfo.Name;
                  databaseType = columnAttr?.TypeName;
                  columnOrder = columnAttr?.Order;
 
@@ -61,7 +61,7 @@ namespace Vitorm.Entity.DataAnnotations
                      }
                  }
 
-                 return new ColumnDescriptor(propertyInfo, name: name, isKey: isKey, isIdentity: isIdentity, databaseType: databaseType, isNullable: isNullable, columnOrder: columnOrder);
+                 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);

+ 20 - 0
src/Vitorm/Entity/Extensions/IEntityDescriptor_Extensions.cs

@@ -0,0 +1,20 @@
+using System.Linq;
+
+using Vitorm.Entity;
+
+namespace Vit.Extensions.Vitorm_Extensions
+{
+    public static partial class IEntityDescriptor_Extensions
+    {
+        /// <summary>
+        /// get database column name by entity property name
+        /// </summary>
+        /// <param name="data"></param>
+        /// <param name="propertyName"></param>
+        /// <returns></returns>
+        public static string GetColumnNameByPropertyName(this IEntityDescriptor data, string propertyName)
+        {
+            return data?.allColumns.FirstOrDefault(m => m.propertyName == propertyName)?.columnName;
+        }
+    }
+}

+ 8 - 1
src/Vitorm/Entity/IColumnDescriptor.cs

@@ -5,7 +5,14 @@ namespace Vitorm.Entity
     public interface IColumnDescriptor
     {
         Type type { get; }
-        string name { get; }
+        /// <summary>
+        /// property name in Entity Type
+        /// </summary>
+        string propertyName { get; }
+        /// <summary>
+        /// column name in database
+        /// </summary>
+        string columnName { get; }
         bool isKey { get; }
 
         /// <summary>

+ 1 - 1
src/Vitorm/Sql/DataReader/EntityReader/ModelReader.cs

@@ -33,7 +33,7 @@ namespace Vitorm.Sql.DataReader
             {
                 foreach (var column in entityDescriptor.allColumns)
                 {
-                    var sqlFieldName = sqlTranslator.GetSqlField(tableName, column.name);
+                    var sqlFieldName = sqlTranslator.GetSqlField(tableName, column.columnName);
                     proppertyReaders.Add(new EntityPropertyReader(entityReader, column, sqlFieldName));
                 }
             }

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

@@ -215,7 +215,7 @@ namespace Vitorm.Sql
                 var entity = (Entity)Activator.CreateInstance(typeof(Entity));
                 foreach (var column in entityDescriptor.allColumns)
                 {
-                    var value = TypeUtil.ConvertToType(reader[column.name], column.type);
+                    var value = TypeUtil.ConvertToType(reader[column.columnName], column.type);
                     if (value != null)
                         column.SetValue(entity, value);
                 }

+ 31 - 9
src/Vitorm/Sql/SqlTranslate/SqlTranslateService.cs

@@ -10,6 +10,8 @@ using System.Text;
 using System.Linq.Expressions;
 using static Vitorm.Sql.SqlDbContext;
 using System.Data;
+using Vit.Linq.ExpressionTree.ExpressionConvertor;
+using Vit.Extensions.Vitorm_Extensions;
 
 namespace Vitorm.Sql.SqlTranslate
 {
@@ -67,7 +69,22 @@ namespace Vitorm.Sql.SqlTranslate
             if (string.IsNullOrWhiteSpace(memberName))
             {
                 var entityType = member.Member_GetType();
-                memberName = dbContext.GetEntityDescriptor(entityType)?.keyName;
+                var entityDescriptor = dbContext.GetEntityDescriptor(entityType);
+                memberName = entityDescriptor?.keyName;
+            }
+            else if (member.objectValue != null)
+            {
+                var entityType = member.objectValue.Member_GetType();
+                if (entityType != null)
+                {
+                    var entityDescriptor = dbContext.GetEntityDescriptor(entityType);
+                    if (entityDescriptor != null)
+                    {
+                        var columnName = entityDescriptor.GetColumnNameByPropertyName(memberName);
+                        if (string.IsNullOrEmpty(columnName)) throw new NotSupportedException("[QueryTranslator] can not find database column name for property : " + memberName);
+                        memberName = columnName;
+                    }
+                }
             }
 
             // 1: {"nodeType":"Member","parameterName":"a0","memberName":"id"}
@@ -184,14 +201,19 @@ namespace Vitorm.Sql.SqlTranslate
                                 }
                             case nameof(Enumerable.Max) or nameof(Enumerable.Min) or nameof(Enumerable.Sum) or nameof(Enumerable.Average) when methodCall.arguments.Length == 2:
                                 {
-                                    var stream = methodCall.arguments[0] as ExpressionNode_Member;
-                                    if (stream?.nodeType != NodeType.Member) break;
+                                    var source = methodCall.arguments[0];
+                                    if (source?.nodeType != NodeType.Member) break;
+
+                                    var entityType = methodCall.MethodCall_GetParamTypes()[0].GetGenericArguments()[0];
+                                    source = TypeUtil.Clone(source).Member_SetType(entityType);
 
 
                                     var lambdaFieldSelect = methodCall.arguments[1] as ExpressionNode_Lambda;
 
                                     var parameterName = lambdaFieldSelect.parameterNames[0];
-                                    var parameterValue = (ExpressionNode)stream;
+                                    var parameterValue = source;
+
+
                                     Func<ExpressionNode_Member, ExpressionNode> GetParameter = (member) =>
                                     {
                                         if (member.nodeType == NodeType.Member && member.parameterName == parameterName)
@@ -321,7 +343,7 @@ namespace Vitorm.Sql.SqlTranslate
                 var sqlParam = new Dictionary<string, object>();
                 foreach (var column in columns)
                 {
-                    sqlParam[column.name] = column.GetValue(entity);
+                    sqlParam[column.columnName] = column.GetValue(entity);
                 }
                 return sqlParam;
             };
@@ -332,8 +354,8 @@ namespace Vitorm.Sql.SqlTranslate
 
             foreach (var column in columns)
             {
-                columnNames.Add(DelimitIdentifier(column.name));
-                valueParams.Add(GenerateParameterName(column.name));
+                columnNames.Add(DelimitIdentifier(column.columnName));
+                valueParams.Add(GenerateParameterName(column.columnName));
             }
             #endregion
 
@@ -384,7 +406,7 @@ namespace Vitorm.Sql.SqlTranslate
                 var sqlParam = new Dictionary<string, object>();
                 foreach (var column in entityDescriptor.allColumns)
                 {
-                    var columnName = column.name;
+                    var columnName = column.columnName;
                     var value = column.GetValue(entity);
 
                     sqlParam[columnName] = value;
@@ -398,7 +420,7 @@ namespace Vitorm.Sql.SqlTranslate
             string columnName;
             foreach (var column in entityDescriptor.columns)
             {
-                columnName = column.name;
+                columnName = column.columnName;
                 columnsToUpdate.Add($"{DelimitIdentifier(columnName)}={GenerateParameterName(columnName)}");
             }
 

+ 2 - 2
src/Vitorm/StreamQuery/StreamReader.cs

@@ -10,11 +10,11 @@ namespace Vitorm.StreamQuery
 
     public class ExpressionNode_RenameableMember : ExpressionNode
     {
-        private IStream stream;
+        protected IStream stream;
         public override string parameterName
         {
             get => stream?.alias;
-            set => throw new NotSupportedException();
+            set { }
         }
         public static ExpressionNode Member(IStream stream, Type memberType)
         {

+ 31 - 0
src/Vitorm/TypeUtil.cs

@@ -1,4 +1,10 @@
 using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Security.Cryptography;
+
+using Vit.Linq.ExpressionTree.ComponentModel;
 
 
 namespace Vitorm
@@ -52,6 +58,31 @@ namespace Vitorm
             return Activator.CreateInstance(type);
         }
 
+        public static Model Clone<Model>(Model source)
+        {
+            if (null == source) return default;
+            var type = source.GetType();
+            var destination = (Model)Activator.CreateInstance(type);
+
+            foreach (var p in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
+            {
+                if (p.CanRead && p.CanWrite)
+                {
+                    var value = p.GetValue(source);
+                    if (value == null) continue;
+                    p.SetValue(destination, value);
+                }
+            }
+            foreach (var p in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
+            {
+                {
+                    var value = p.GetValue(source);
+                    if (value == null) continue;
+                    p.SetValue(destination, value);
+                }
+            }
+            return destination;
+        }
 
     }
 }

+ 48 - 9
test/Vitorm.MySql.MsTest/DataSource.cs

@@ -1,7 +1,6 @@
 using Vitorm.Sql;
 using Vit.Extensions;
 using Vit.Core.Util.ConfigurationManager;
-using System.ComponentModel.DataAnnotations.Schema;
 
 namespace Vitorm.MsTest
 {
@@ -9,13 +8,19 @@ namespace Vitorm.MsTest
     public class User
     {
         [System.ComponentModel.DataAnnotations.Key]
-        [System.ComponentModel.DataAnnotations.Schema.DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+        [System.ComponentModel.DataAnnotations.Schema.Column("userId")]
+        [System.ComponentModel.DataAnnotations.Schema.DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
         public int id { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userName")]
         public string name { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userBirth")]
         public DateTime? birth { get; set; }
-
+        [System.ComponentModel.DataAnnotations.Schema.Column("userFatherId")]
         public int? fatherId { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userMotherId")]
         public int? motherId { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userClassId")]
+        public int? classId { get; set; }
 
         [System.ComponentModel.DataAnnotations.Schema.NotMapped]
         public string test { get; set; }
@@ -29,6 +34,22 @@ namespace Vitorm.MsTest
         }
     }
 
+    [System.ComponentModel.DataAnnotations.Schema.Table("UserClass")]
+    public class UserClass
+    {
+        [System.ComponentModel.DataAnnotations.Key]
+        [System.ComponentModel.DataAnnotations.Schema.Column("classId")]
+        [System.ComponentModel.DataAnnotations.Schema.DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
+        public int id { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("className")]
+        public string name { get; set; }
+
+        public static List<UserClass> NewClasses(int startId, int count = 1)
+        {
+            return Enumerable.Range(startId, count).Select(id => new UserClass { id = 0, name = "class" + id }).ToList();
+        }
+    }
+
 
     public class DataSource
     {
@@ -44,11 +65,13 @@ namespace Vitorm.MsTest
 
             dbContext.BeginTransaction();
 
-            dbContext.Execute(sql: "DROP TABLE  if exists `User`;");
+            #region #1 init User
+            {
+                dbContext.Execute(sql: "DROP TABLE if exists `User`;");
 
-            dbContext.Create<User>();
+                dbContext.Create<User>();
 
-            var users = new List<User> {
+                var users = new List<User> {
                     new User {   name="u146", fatherId=4, motherId=6 },
                     new User {   name="u246", fatherId=4, motherId=6 },
                     new User {   name="u356", fatherId=5, motherId=6 },
@@ -57,11 +80,27 @@ namespace Vitorm.MsTest
                     new User {   name="u600" },
                 };
 
-            dbContext.AddRange(users);
+                dbContext.AddRange(users);
+
+                users.ForEach(user =>
+                {
+                    user.birth = DateTime.Parse("2021-01-01 00:00:00").AddHours(user.id);
+                    user.classId = user.id % 2 + 1;
+                });
+
+                dbContext.UpdateRange(users);
+            }
+            #endregion
+
+            #region #2 init Class
+            {
+                dbContext.Execute(sql: "DROP TABLE if exists `UserClass`;");
 
-            users.ForEach(user => { user.birth = DateTime.Parse("2021-01-01 00:00:00").AddHours(user.id); });
+                dbContext.Create<UserClass>();
+                dbContext.AddRange(UserClass.NewClasses(1, 6));
+            }
+            #endregion
 
-            dbContext.UpdateRange(users);
 
             return dbContext;
         }

+ 48 - 13
test/Vitorm.SqlServer.MsTest/DataSource.cs

@@ -1,7 +1,6 @@
 using Vitorm.Sql;
 using Vit.Extensions;
 using Vit.Core.Util.ConfigurationManager;
-using System.ComponentModel.DataAnnotations.Schema;
 
 namespace Vitorm.MsTest
 {
@@ -9,21 +8,24 @@ namespace Vitorm.MsTest
     public class User
     {
         [System.ComponentModel.DataAnnotations.Key]
-        [System.ComponentModel.DataAnnotations.Schema.DatabaseGenerated(DatabaseGeneratedOption.Identity)]
-        [System.ComponentModel.DataAnnotations.Schema.Column("id", TypeName = "int")]
+        [System.ComponentModel.DataAnnotations.Schema.DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
+        [System.ComponentModel.DataAnnotations.Schema.Column("userId", TypeName = "int")]
         public int id { get; set; }
 
-        [System.ComponentModel.DataAnnotations.Schema.Column("name", TypeName = "varchar(1000)")]
+        [System.ComponentModel.DataAnnotations.Schema.Column("userName", TypeName = "varchar(1000)")]
         [System.ComponentModel.DataAnnotations.Required]
         public string name { get; set; }
-     
+        [System.ComponentModel.DataAnnotations.Schema.Column("userBirth")]
         public DateTime? birth { get; set; }
-
+        [System.ComponentModel.DataAnnotations.Schema.Column("userFatherId")]
         public int? fatherId { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userMotherId")]
         public int? motherId { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userClassId")]
+        public int? classId { get; set; }
 
         [System.ComponentModel.DataAnnotations.Schema.NotMapped]
-        public string test{ get; set; }
+        public string test { get; set; }
 
         public static User NewUser(int id, bool forAdd = false) => new User { id = forAdd ? 0 : id, name = "testUser" + id };
 
@@ -33,6 +35,22 @@ namespace Vitorm.MsTest
         }
     }
 
+    [System.ComponentModel.DataAnnotations.Schema.Table("UserClass")]
+    public class UserClass
+    {
+        [System.ComponentModel.DataAnnotations.Key]
+        [System.ComponentModel.DataAnnotations.Schema.Column("classId")]
+        [System.ComponentModel.DataAnnotations.Schema.DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
+        public int id { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("className")]
+        public string name { get; set; }
+
+        public static List<UserClass> NewClasses(int startId, int count = 1)
+        {
+            return Enumerable.Range(startId, count).Select(id => new UserClass { id = 0, name = "class" + id }).ToList();
+        }
+    }
+
 
     public class DataSource
     {
@@ -49,11 +67,13 @@ namespace Vitorm.MsTest
 
             dbContext.BeginTransaction();
 
-            dbContext.Execute(sql: "IF OBJECT_ID(N'User', N'U') IS  NOT  NULL \r\nDROP TABLE [User];");
+            #region #1 init User
+            {
+                dbContext.Execute(sql: "IF OBJECT_ID(N'User', N'U') IS  NOT  NULL \r\nDROP TABLE [User];");
 
-            dbContext.Create<User>();
+                dbContext.Create<User>();
 
-            var users = new List<User> {
+                var users = new List<User> {
                     new User {   name="u146", fatherId=4, motherId=6 },
                     new User {   name="u246", fatherId=4, motherId=6 },
                     new User {   name="u356", fatherId=5, motherId=6 },
@@ -62,11 +82,26 @@ namespace Vitorm.MsTest
                     new User {   name="u600" },
                 };
 
-            dbContext.AddRange(users);
+                dbContext.AddRange(users);
+
+                users.ForEach(user =>
+                {
+                    user.birth = DateTime.Parse("2021-01-01 00:00:00").AddHours(user.id);
+                    user.classId = user.id % 2 + 1;
+                });
+
+                dbContext.UpdateRange(users);
+            }
+            #endregion
 
-            users.ForEach(user => { user.birth = DateTime.Parse("2021-01-01 00:00:00").AddHours(user.id); });
+            #region #2 init Class
+            {
+                dbContext.Execute(sql: "IF OBJECT_ID(N'UserClass', N'U') IS  NOT  NULL \r\nDROP TABLE [UserClass];");
 
-            dbContext.UpdateRange(users);
+                dbContext.Create<UserClass>();
+                dbContext.AddRange(UserClass.NewClasses(1, 6));
+            }
+            #endregion
 
             return dbContext;
         }

+ 11 - 4
test/Vitorm.Sqlite.MsTest/CommonTest/DbContext_Test.cs

@@ -6,6 +6,7 @@ using Vitorm.Entity;
 using Vitorm.Entity.DataAnnotations;
 using Vitorm.Entity.Loader;
 using Vitorm.Entity.LoaderAttribute;
+using Vit.Extensions.Vitorm_Extensions;
 
 namespace Vitorm.MsTest.CommonTest
 {
@@ -19,7 +20,7 @@ namespace Vitorm.MsTest.CommonTest
             var entityDescriptor = dbContext.GetEntityDescriptor(typeof(User));
             var key = entityDescriptor.key;
 
-            Assert.AreEqual("id", key.name);
+            Assert.AreEqual("userId", key.columnName);
         }
 
 
@@ -31,6 +32,7 @@ namespace Vitorm.MsTest.CommonTest
             // #1 EntityLoaderAttribute
             {
                 var users = dbContext.Query<CustomUser2>().Where(m => m.name == "u146").ToList();
+                var sql = dbContext.Query<CustomUser2>().Where(m => m.name == "u146").ToExecuteString();
                 Assert.AreEqual(1, users.Count());
                 Assert.AreEqual(1, users[0].id);
             }
@@ -61,15 +63,20 @@ namespace Vitorm.MsTest.CommonTest
         {
             [Label("Key")]
             [Label("Identity")]
+            [Property(name = "ColumnName", value = "userId")]
             public int id { get; set; }
 
-            [Property(name = "ColumnName", value = "name")]
+            [Property(name = "ColumnName", value = "userName")]
             [Property(name = "TypeName", value = "varchar(1000)")]
             [Label("Required")]
             public string name { get; set; }
+
+            [Property(name = "ColumnName", value = "userBirth")]
             public DateTime? birth { get; set; }
 
+            [Property(name = "ColumnName", value = "userFatherId")]
             public int? fatherId { get; set; }
+            [Property(name = "ColumnName", value = "userMotherId")]
             public int? motherId { get; set; }
 
             [Label("NotMapped")]
@@ -128,7 +135,7 @@ namespace Vitorm.MsTest.CommonTest
                         bool isKey = labels.Any(m => m.label == "Key");
 
                         // #2 column name and type
-                        var name = properties.FirstOrDefault(attr => attr.name == "ColumnName")?.value ?? propertyInfo.Name;
+                        var columnName = properties.FirstOrDefault(attr => attr.name == "ColumnName")?.value ?? propertyInfo.Name;
                         var databaseType = properties.FirstOrDefault(attr => attr.name == "TypeName")?.value;
                         int? columnOrder = int.TryParse(properties.FirstOrDefault(attr => attr.name == "ColumnOrder")?.value, out var order) ? order : null;
 
@@ -148,7 +155,7 @@ namespace Vitorm.MsTest.CommonTest
                             }
                         }
 
-                        return new ColumnDescriptor(propertyInfo, name: name, isKey: isKey, isIdentity: isIdentity, databaseType: databaseType, isNullable: isNullable, columnOrder: columnOrder);
+                        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);

+ 2 - 2
test/Vitorm.Sqlite.MsTest/CommonTest/Query_Group_Test.cs

@@ -15,7 +15,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                         from user in userQuery
@@ -58,7 +58,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                         from user in userQuery.Where(u => u.id > 1)

+ 2 - 2
test/Vitorm.Sqlite.MsTest/CommonTest/Query_InnerJoin_ByJoin_Test.cs

@@ -15,7 +15,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                     from user in userQuery
@@ -58,7 +58,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                     from user in userQuery

+ 2 - 2
test/Vitorm.Sqlite.MsTest/CommonTest/Query_InnerJoin_BySelectMany_Test.cs

@@ -15,7 +15,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                     from user in userQuery
@@ -57,7 +57,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                     from user in userQuery

+ 2 - 2
test/Vitorm.Sqlite.MsTest/CommonTest/Query_LeftJoin_ByGroupJoin_Test.cs

@@ -14,7 +14,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                     from user in userQuery
@@ -69,7 +69,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                     from user in userQuery

+ 6 - 3
test/Vitorm.Sqlite.MsTest/CommonTest/Query_LeftJoin_BySelectMany_Test.cs

@@ -17,7 +17,7 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                         from user in userQuery
@@ -66,19 +66,22 @@ namespace Vitorm.MsTest.CommonTest
             using var dbContext = DataSource.CreateDbContext();
             var userQuery = dbContext.Query<User>();
 
-            // Linq Expresssion
+            // Linq Expression
             {
                 var query =
                     from user in userQuery
                     from father in userQuery.Where(father => user.fatherId == father.id).DefaultIfEmpty()
                     from mother in userQuery.Where(mother => user.motherId == mother.id).DefaultIfEmpty()
-                    where user.id > 2
+                    from userClass in dbContext.Query<UserClass>().Where(userClass => user.classId == userClass.id).DefaultIfEmpty()
+                    where user.id > 1 && userClass.id == 1
                     orderby user.id
                     select new
                     {
                         user,
                         father,
                         mother,
+                        userClass,
+                        userClass.name,
                         testId = user.id + 100,
                         hasFather = father.name != null ? true : false
                     };

+ 44 - 6
test/Vitorm.Sqlite.MsTest/DataSource.cs

@@ -1,4 +1,5 @@
 using Vit.Extensions;
+
 using Vitorm.Sql;
 
 namespace Vitorm.MsTest
@@ -7,12 +8,18 @@ namespace Vitorm.MsTest
     public class User
     {
         [System.ComponentModel.DataAnnotations.Key]
+        [System.ComponentModel.DataAnnotations.Schema.Column("userId")]
         public int id { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userName")]
         public string name { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userBirth")]
         public DateTime? birth { get; set; }
-
+        [System.ComponentModel.DataAnnotations.Schema.Column("userFatherId")]
         public int? fatherId { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userMotherId")]
         public int? motherId { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("userClassId")]
+        public int? classId { get; set; }
 
         [System.ComponentModel.DataAnnotations.Schema.NotMapped]
         public string test { get; set; }
@@ -26,6 +33,21 @@ namespace Vitorm.MsTest
         }
     }
 
+    [System.ComponentModel.DataAnnotations.Schema.Table("UserClass")]
+    public class UserClass
+    {
+        [System.ComponentModel.DataAnnotations.Key]
+        [System.ComponentModel.DataAnnotations.Schema.Column("classId")]
+        public int id { get; set; }
+        [System.ComponentModel.DataAnnotations.Schema.Column("className")]
+        public string name { get; set; }
+
+        public static List<UserClass> NewClasses(int startId, int count = 1)
+        {
+            return Enumerable.Range(startId, count).Select(id => new UserClass { id = id, name = "class" + id }).ToList();
+        }
+    }
+
 
     public class DataSource
     {
@@ -47,10 +69,12 @@ namespace Vitorm.MsTest
 
             dbContext.BeginTransaction();
 
-            var dbSet = dbContext.DbSet<User>();
-            dbSet.Create();
 
-            var users = new List<User> {
+            #region #1 init User
+            {
+                dbContext.Create<User>();
+
+                var users = new List<User> {
                     new User { id=1, name="u146", fatherId=4, motherId=6 },
                     new User { id=2, name="u246", fatherId=4, motherId=6 },
                     new User { id=3, name="u356", fatherId=5, motherId=6 },
@@ -58,9 +82,23 @@ namespace Vitorm.MsTest
                     new User { id=5, name="u500" },
                     new User { id=6, name="u600" },
                 };
-            users.ForEach(user => { user.birth = DateTime.Parse("2021-01-01 00:00:00").AddHours(user.id); });
+                users.ForEach(user =>
+                {
+                    user.birth = DateTime.Parse("2021-01-01 00:00:00").AddHours(user.id);
+                    user.classId = user.id % 2 + 1;
+                });
+
+                dbContext.AddRange(users);
+            }
+            #endregion
+
+            #region #2 init Class
+            {
+                dbContext.Create<UserClass>();
+                dbContext.AddRange(UserClass.NewClasses(1, 6));
+            }
+            #endregion
 
-            dbContext.AddRange(users);
 
             return dbContext;
         }