mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	mysql/sqlserver CodeFirst 完成测试
This commit is contained in:
		@@ -17,21 +17,31 @@ namespace FreeSql.Internal {
 | 
			
		||||
			switch (exp.NodeType) {
 | 
			
		||||
				case ExpressionType.Quote: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand);
 | 
			
		||||
				case ExpressionType.Lambda: return ReadAnonymousField(_tables, field, parent, ref index, (exp as LambdaExpression)?.Body);
 | 
			
		||||
				case ExpressionType.Negate:
 | 
			
		||||
				case ExpressionType.NegateChecked:
 | 
			
		||||
					field.Append(", ").Append(ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true)).Append(" as").Append(++index);
 | 
			
		||||
					return false;
 | 
			
		||||
				case ExpressionType.Convert: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand);
 | 
			
		||||
				case ExpressionType.Constant:
 | 
			
		||||
					var constExp = exp as ConstantExpression;
 | 
			
		||||
					field.Append(", ").Append(constExp?.Value).Append(" as").Append(++index);
 | 
			
		||||
					return false;
 | 
			
		||||
				case ExpressionType.Call:
 | 
			
		||||
					field.Append(", ").Append(ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true)).Append(" as").Append(++index);
 | 
			
		||||
					return false;
 | 
			
		||||
				case ExpressionType.MemberAccess:
 | 
			
		||||
					var map = new List<SelectColumnInfo>();
 | 
			
		||||
					ExpressionSelectColumn_MemberAccess(_tables, map, SelectTableInfoType.From, exp, true);
 | 
			
		||||
					if (map.Count > 1) {
 | 
			
		||||
					if (_common.GetTableByEntity(exp.Type) != null) { //加载表所有字段
 | 
			
		||||
						var map = new List<SelectColumnInfo>();
 | 
			
		||||
						ExpressionSelectColumn_MemberAccess(_tables, map, SelectTableInfoType.From, exp, true);
 | 
			
		||||
						parent.Consturctor = map.First().Table.Table.Type.GetConstructor(new Type[0]);
 | 
			
		||||
						parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
 | 
			
		||||
					}
 | 
			
		||||
					for (var idx = 0; idx < map.Count; idx++) {
 | 
			
		||||
						field.Append(", ").Append(map[idx].Table.Alias).Append(".").Append(_common.QuoteSqlName(map[idx].Column.Attribute.Name)).Append(" as").Append(++index);
 | 
			
		||||
						if (map.Count > 1) parent.Childs.Add(new ReadAnonymousTypeInfo { CsName = map[idx].Column.CsName });
 | 
			
		||||
						for (var idx = 0; idx < map.Count; idx++) {
 | 
			
		||||
							field.Append(", ").Append(map[idx].Table.Alias).Append(".").Append(_common.QuoteSqlName(map[idx].Column.Attribute.Name)).Append(" as").Append(++index);
 | 
			
		||||
							parent.Childs.Add(new ReadAnonymousTypeInfo { CsName = map[idx].Column.CsName });
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						field.Append(", ").Append(ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true)).Append(" as").Append(++index);
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
					return false;
 | 
			
		||||
				case ExpressionType.New:
 | 
			
		||||
@@ -39,7 +49,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
					parent.Consturctor = newExp.Type.GetConstructors()[0];
 | 
			
		||||
					parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Arguments;
 | 
			
		||||
					for (var a = 0; a < newExp.Members.Count; a++) {
 | 
			
		||||
						var child = new ReadAnonymousTypeInfo { CsName = newExp.Members[a].Name };
 | 
			
		||||
						var child = new ReadAnonymousTypeInfo { CsName = newExp.Members[a].Name, CsType = newExp.Arguments[a].Type };
 | 
			
		||||
						parent.Childs.Add(child);
 | 
			
		||||
						ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a]);
 | 
			
		||||
					}
 | 
			
		||||
@@ -53,7 +63,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
				case ReadAnonymousTypeInfoConsturctorType.Arguments:
 | 
			
		||||
					var args = new object[parent.Childs.Count];
 | 
			
		||||
					for (var a = 0; a < parent.Childs.Count; a++) {
 | 
			
		||||
						args[a] = ReadAnonymous(parent.Childs[a], dr, ref index);
 | 
			
		||||
						args[a] = Utils.GetDataReaderValue(parent.Childs[a].CsType, ReadAnonymous(parent.Childs[a], dr, ref index));
 | 
			
		||||
					}
 | 
			
		||||
					return parent.Consturctor.Invoke(args);
 | 
			
		||||
				case ReadAnonymousTypeInfoConsturctorType.Properties:
 | 
			
		||||
@@ -162,6 +172,9 @@ namespace FreeSql.Internal {
 | 
			
		||||
				case ExpressionType.Negate:
 | 
			
		||||
				case ExpressionType.NegateChecked: return "-" + ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, tbtype, isQuoteName);
 | 
			
		||||
				case ExpressionType.Constant: return _common.FormatSql("{0}", (exp as ConstantExpression)?.Value);
 | 
			
		||||
				case ExpressionType.Conditional:
 | 
			
		||||
					var condExp = exp as ConditionalExpression;
 | 
			
		||||
					return $"case when {ExpressionLambdaToSql(condExp.Test, _tables, _selectColumnMap, tbtype, isQuoteName)} then {ExpressionLambdaToSql(condExp.IfTrue, _tables, _selectColumnMap, tbtype, isQuoteName)} else {ExpressionLambdaToSql(condExp.IfFalse, _tables, _selectColumnMap, tbtype, isQuoteName)} end";
 | 
			
		||||
				case ExpressionType.Call:
 | 
			
		||||
					var exp3 = exp as MethodCallExpression;
 | 
			
		||||
					switch (exp3.Object?.Type.FullName ?? exp3.Method.DeclaringType.FullName) {
 | 
			
		||||
@@ -169,6 +182,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
						case "System.Math": return ExpressionLambdaToSqlCallMath(exp3, _tables, _selectColumnMap, tbtype, isQuoteName);
 | 
			
		||||
						case "System.DateTime": return ExpressionLambdaToSqlCallDateTime(exp3, _tables, _selectColumnMap, tbtype, isQuoteName);
 | 
			
		||||
						case "System.TimeSpan": return ExpressionLambdaToSqlCallTimeSpan(exp3, _tables, _selectColumnMap, tbtype, isQuoteName);
 | 
			
		||||
						case "System.Convert": return ExpressionLambdaToSqlCallConvert(exp3, _tables, _selectColumnMap, tbtype, isQuoteName);
 | 
			
		||||
					}
 | 
			
		||||
					throw new Exception($"MySqlExpression 未现实函数表达式 {exp3} 解析");
 | 
			
		||||
				case ExpressionType.MemberAccess:
 | 
			
		||||
@@ -304,5 +318,6 @@ namespace FreeSql.Internal {
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName);
 | 
			
		||||
		internal abstract string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -248,7 +248,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var tran = TransactionCurrentThread;
 | 
			
		||||
			if (IsTracePerformance) logtxt += $"	PrepareCommand_part1: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmdParms.Length}\r\n";
 | 
			
		||||
			if (IsTracePerformance) logtxt += $"	PrepareCommand_part1: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmd.Parameters.Count}\r\n";
 | 
			
		||||
 | 
			
		||||
			if (tran != null) {
 | 
			
		||||
				if (IsTracePerformance) dt = DateTime.Now;
 | 
			
		||||
 
 | 
			
		||||
@@ -207,7 +207,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (IsTracePerformance) logtxt += $"	PrepareCommand_tran==null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
 | 
			
		||||
			if (IsTracePerformance) logtxt += $"	PrepareCommand_tran==null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmd.Parameters.Count}\r\n";
 | 
			
		||||
 | 
			
		||||
			return cmd;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,6 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
					sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
 | 
			
		||||
					++colidx;
 | 
			
		||||
				}
 | 
			
		||||
			if (colidx == 0) return null;
 | 
			
		||||
			sb.Append(") VALUES");
 | 
			
		||||
			_params = new DbParameter[colidx * _source.Count];
 | 
			
		||||
			var didx = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -178,6 +178,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			var type = typeof(T1);
 | 
			
		||||
			var map = new ReadAnonymousTypeInfo { Consturctor = type.GetConstructor(new Type[0]), ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties };
 | 
			
		||||
			var field = new StringBuilder();
 | 
			
		||||
			var dicfield = new Dictionary<string, bool>();
 | 
			
		||||
			var tb = _tables.First();
 | 
			
		||||
			var index = 0;
 | 
			
		||||
			var ps = typeof(T1).GetProperties();
 | 
			
		||||
@@ -185,7 +186,11 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				var child = new ReadAnonymousTypeInfo { CsName = p.Name };
 | 
			
		||||
				if (tb.Table.ColumnsByCs.TryGetValue(p.Name, out var col)) { //普通字段
 | 
			
		||||
					if (index > 0) field.Append(", ");
 | 
			
		||||
					field.Append(tb.Alias).Append(".").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as").Append(++index);
 | 
			
		||||
					var quoteName = _commonUtils.QuoteSqlName(col.Attribute.Name);
 | 
			
		||||
					field.Append(tb.Alias).Append(".").Append(quoteName);
 | 
			
		||||
					++index;
 | 
			
		||||
					if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
 | 
			
		||||
					else dicfield.Add(quoteName, true);
 | 
			
		||||
				} else {
 | 
			
		||||
					var tb2 = _tables.Where(a => a.Table.Type == p.PropertyType && a.Alias.Contains(p.Name)).FirstOrDefault();
 | 
			
		||||
					if (tb2 == null && ps.Where(pw => pw.PropertyType == p.PropertyType).Count() == 1) tb2 = _tables.Where(a => a.Table.Type == p.PropertyType).FirstOrDefault();
 | 
			
		||||
@@ -194,7 +199,11 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
					child.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
 | 
			
		||||
					foreach (var col2 in tb2.Table.Columns.Values) {
 | 
			
		||||
						if (index > 0) field.Append(", ");
 | 
			
		||||
						field.Append(tb2.Alias).Append(".").Append(_commonUtils.QuoteSqlName(col2.Attribute.Name)).Append(" as").Append(++index);
 | 
			
		||||
						var quoteName = _commonUtils.QuoteSqlName(col2.Attribute.Name);
 | 
			
		||||
						field.Append(tb2.Alias).Append(".").Append(quoteName);
 | 
			
		||||
						++index;
 | 
			
		||||
						if (dicfield.ContainsKey(quoteName)) field.Append(" as").Append(index);
 | 
			
		||||
						else dicfield.Add(quoteName, true);
 | 
			
		||||
						child.Childs.Add(new ReadAnonymousTypeInfo { CsName = col2.CsName });
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,9 +47,8 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
						default: throw new NotImplementedException($"未现实 {expCall.Method.Name}");
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				return this;
 | 
			
		||||
			}
 | 
			
		||||
			throw new NotImplementedException($"未现实 {exp}");
 | 
			
		||||
			return this;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public ISelect<T1> As(string alias) {
 | 
			
		||||
 
 | 
			
		||||
@@ -66,13 +66,10 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			if (cols.Any() == false) return this;
 | 
			
		||||
			foreach (var col in cols) {
 | 
			
		||||
				if (col.Column.Attribute.IsNullable) {
 | 
			
		||||
					var repltype = col.Column.CsType;
 | 
			
		||||
					if (repltype.FullName.StartsWith("System.Nullable`1[[System.")) repltype = repltype.GenericTypeArguments[0];
 | 
			
		||||
					var replval = Activator.CreateInstance(repltype);
 | 
			
		||||
					var replval = col.Column.Attribute.DbDefautValue;
 | 
			
		||||
					if (replval == null) continue;
 | 
			
		||||
					var replname = _commonUtils.QuoteSqlName(col.Column.Attribute.Name);
 | 
			
		||||
					replval = _commonUtils.FormatSql("{0}", replval);
 | 
			
		||||
					expt = expt.Replace(replname, _commonUtils.IsNull(replname, replval));
 | 
			
		||||
					expt = expt.Replace(replname, _commonUtils.IsNull(replname, _commonUtils.FormatSql("{0}", replval)));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			_set.Append(", ").Append(_commonUtils.QuoteSqlName(cols.First().Column.Attribute.Name)).Append(" = ").Append(expt);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ using System.Text;
 | 
			
		||||
namespace FreeSql.Internal.Model {
 | 
			
		||||
	class ReadAnonymousTypeInfo {
 | 
			
		||||
		public string CsName { get; set; }
 | 
			
		||||
		public Type CsType { get; set; }
 | 
			
		||||
		public ConstructorInfo Consturctor { get; set; }
 | 
			
		||||
		public ReadAnonymousTypeInfoConsturctorType ConsturctorType { get; set; }
 | 
			
		||||
		public List<ReadAnonymousTypeInfo> Childs = new List<ReadAnonymousTypeInfo>();
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,5 @@ namespace FreeSql.Internal.Model {
 | 
			
		||||
		public string DbName { get; set; }
 | 
			
		||||
		public string DbOldName { get; set; }
 | 
			
		||||
		public string SelectFilter { get; set; }
 | 
			
		||||
		public List<List<ColumnInfo>> Uniques { get; set; } = new List<List<ColumnInfo>>();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -35,12 +35,22 @@ namespace FreeSql.Internal {
 | 
			
		||||
						Name = p.Name,
 | 
			
		||||
						DbType = tp.Value.dbtypeFull,
 | 
			
		||||
						IsIdentity = false,
 | 
			
		||||
						IsNullable = tp.Value.isnullable ?? false,
 | 
			
		||||
						IsNullable = tp.Value.isnullable ?? true,
 | 
			
		||||
						IsPrimary = false,
 | 
			
		||||
					};
 | 
			
		||||
				if (string.IsNullOrEmpty(colattr.DbType) == false) colattr.DbType = colattr.DbType.ToUpper();
 | 
			
		||||
				if (tp != null && tp.Value.isnullable == null) colattr.IsNullable = tp.Value.dbtypeFull.Contains("NOT NULL") == false;
 | 
			
		||||
				if (string.IsNullOrEmpty(colattr.DbType) == false) colattr.IsNullable = colattr.DbType.Contains("NOT NULL") == false;
 | 
			
		||||
				if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
 | 
			
		||||
				if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp?.dbtypeFull ?? "varchar(255)";
 | 
			
		||||
				if (colattr.DbType.IndexOf("NOT NULL") == -1 && tp?.isnullable == false) colattr.DbType += " NOT NULL";
 | 
			
		||||
				if ((colattr.IsNullable == false || colattr.IsIdentity || colattr.IsPrimary) && colattr.DbType.Contains("NOT NULL") == false) colattr.DbType += " NOT NULL";
 | 
			
		||||
				if (colattr.IsNullable == true && colattr.DbType.Contains("NOT NULL")) colattr.DbType = colattr.DbType.Replace("NOT NULL", "");
 | 
			
		||||
				colattr.DbType = Regex.Replace(colattr.DbType, @"\([^\)]+\)", m => Regex.Replace(m.Groups[0].Value, @"\s", ""));
 | 
			
		||||
				colattr.DbDefautValue = trytb.Properties[p.Name].GetValue(Activator.CreateInstance(trytb.Type));
 | 
			
		||||
				if (colattr.DbDefautValue == null && p.PropertyType.FullName == "System.String") colattr.DbDefautValue = string.Empty;
 | 
			
		||||
				if (colattr.DbDefautValue == null) colattr.DbDefautValue = Activator.CreateInstance(p.PropertyType.GenericTypeArguments.FirstOrDefault() ?? p.PropertyType);
 | 
			
		||||
				if (colattr.DbDefautValue == null) colattr.DbDefautValue = "";
 | 
			
		||||
				if (colattr.DbDefautValue.GetType().FullName == "System.DateTime") colattr.DbDefautValue = new DateTime(1970, 1, 1);
 | 
			
		||||
 | 
			
		||||
				var col = new ColumnInfo {
 | 
			
		||||
					Table = trytb,
 | 
			
		||||
@@ -52,6 +62,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
				trytb.ColumnsByCs.Add(p.Name, col);
 | 
			
		||||
			}
 | 
			
		||||
			trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
 | 
			
		||||
			if (trytb.Primarys.Any() == false) trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsIdentity).ToArray();
 | 
			
		||||
			_cacheGetTableByEntity.TryAdd(entity.FullName, trytb);
 | 
			
		||||
			return trytb;
 | 
			
		||||
		}
 | 
			
		||||
@@ -122,22 +133,14 @@ namespace FreeSql.Internal {
 | 
			
		||||
				if (prop == null) throw new Exception(string.Concat(type.FullName, " 没有定义属性 ", members[a]));
 | 
			
		||||
				if (a < members.Length - 1) current = prop.GetValue(current);
 | 
			
		||||
			}
 | 
			
		||||
			if (value == null || value == DBNull.Value) {
 | 
			
		||||
				prop.SetValue(current, null, null);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			var propType = prop.PropertyType;
 | 
			
		||||
			if (propType.FullName.StartsWith("System.Nullable`1[")) propType = propType.GenericTypeArguments.First();
 | 
			
		||||
			if (propType.IsEnum) {
 | 
			
		||||
				var valueStr = string.Concat(value);
 | 
			
		||||
				if (string.IsNullOrEmpty(valueStr) == false) prop.SetValue(current, Enum.Parse(propType, valueStr), null);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			if (propType != value.GetType()) {
 | 
			
		||||
				prop.SetValue(current, Convert.ChangeType(value, propType), null);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			prop.SetValue(current, value, null);
 | 
			
		||||
			prop.SetValue(current, GetDataReaderValue(prop.PropertyType, value), null);
 | 
			
		||||
		}
 | 
			
		||||
		internal static object GetDataReaderValue(Type type, object value) {
 | 
			
		||||
			if (value == null || value == DBNull.Value) return null;
 | 
			
		||||
			if (type.FullName.StartsWith("System.Nullable`1[")) type = type.GenericTypeArguments.First();
 | 
			
		||||
			if (type.IsEnum) return Enum.Parse(type, string.Concat(value));
 | 
			
		||||
			if (type != value.GetType()) return Convert.ChangeType(value, type);
 | 
			
		||||
			return value;
 | 
			
		||||
		}
 | 
			
		||||
		internal static string GetCsName(string name) {
 | 
			
		||||
			name = Regex.Replace(name.TrimStart('@'), @"[^\w]", "_");
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user