Преглед изворни кода

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

Lith пре 10 месеци
родитељ
комит
39a9e23d85
25 измењених фајлова са 301 додато и 75 уклоњено
  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;
         }