From 73c87513d2ed69dd7698c3d6a10fdb1806679a07 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Fri, 31 Jul 2020 03:07:13 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20ColumnAttribute=20Prec?= =?UTF-8?q?ision/Scale=20=E8=AE=BE=E7=BD=AE=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EfCoreFluentApi/EfCoreColumnFluent.cs | 6 + FreeSql.DbContext/FreeSql.DbContext.xml | 9 - FreeSql/DataAnnotations/ColumnAttribute.cs | 11 + FreeSql/DataAnnotations/ColumnFluent.cs | 13 + FreeSql/FreeSql.xml | 328 ++++++++++-------- FreeSql/Internal/CommonExpression.cs | 8 +- FreeSql/Internal/CommonUtils.cs | 6 +- FreeSql/Internal/UtilsExpressionTree.cs | 15 +- .../SqlServer/OdbcSqlServerExpression.cs | 2 +- 9 files changed, 235 insertions(+), 163 deletions(-) diff --git a/FreeSql.DbContext/EfCoreFluentApi/EfCoreColumnFluent.cs b/FreeSql.DbContext/EfCoreFluentApi/EfCoreColumnFluent.cs index 0b87862c..1f89fc59 100644 --- a/FreeSql.DbContext/EfCoreFluentApi/EfCoreColumnFluent.cs +++ b/FreeSql.DbContext/EfCoreFluentApi/EfCoreColumnFluent.cs @@ -54,5 +54,11 @@ namespace FreeSql.Extensions.EfCoreFluentApi //{ // return this; //} + public EfCoreColumnFluent HasPrecision(int precision, int scale = 0) + { + _cf.Precision(precision, scale); + return this; + } + } } diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 4854f49c..474ea8d5 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -486,14 +486,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql/DataAnnotations/ColumnAttribute.cs b/FreeSql/DataAnnotations/ColumnAttribute.cs index b6b11569..4dd251ed 100644 --- a/FreeSql/DataAnnotations/ColumnAttribute.cs +++ b/FreeSql/DataAnnotations/ColumnAttribute.cs @@ -104,5 +104,16 @@ namespace FreeSql.DataAnnotations /// 注意:如果是 getdate() 这种请可考虑使用 ServerTime,因为它对数据库间作了适配 /// public string InsertValueSql { get; set; } + + internal int? _Precision; + /// + /// decimal/numeric 类型的长度 + /// + public int Precision { get => _Precision ?? 0; set => _Precision = value; } + internal int? _Scale; + /// + /// decimal/numeric 类型的小数位长度 + /// + public int Scale { get => _Scale ?? 0; set => _Scale = value; } } } diff --git a/FreeSql/DataAnnotations/ColumnFluent.cs b/FreeSql/DataAnnotations/ColumnFluent.cs index 4a1adc93..4b5b1e09 100644 --- a/FreeSql/DataAnnotations/ColumnFluent.cs +++ b/FreeSql/DataAnnotations/ColumnFluent.cs @@ -176,5 +176,18 @@ namespace FreeSql.DataAnnotations _column.InsertValueSql = value; return this; } + + /// + /// decimal/numeric 类型的长度/小数位长度 + /// + /// 总长度 + /// 小数位长度 + /// + public ColumnFluent Precision(int precision, int scale = 0) + { + _column.Precision = precision; + _column.Scale = scale; + return this; + } } } diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 78dd9783..7feb5fa9 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -105,6 +105,16 @@ 注意:如果是 getdate() 这种请可考虑使用 ServerTime,因为它对数据库间作了适配 + + + decimal/numeric 类型的长度 + + + + + decimal/numeric 类型的小数位长度 + + 数据库列名 @@ -213,6 +223,14 @@ + + + decimal/numeric 类型的长度/小数位长度 + + 总长度 + 小数位长度 + + 自定义表达式函数解析 @@ -2546,137 +2564,6 @@ - - - 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 - - - - - - - - - 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 }) - - - - - - - 查询 - - - - - - - 查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 }) - - - - - - - - 查询 - - - - - - - 查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 }) - - - - - - - - 查询 - - - - - - - 查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 }) - - - - - - - - 在【主库】执行 - - - - - - - - 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 }) - - - - - - - - 在【主库】执行 - - - - - - - - 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 }) - - - - - - - - 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new { age = 25 }) - - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 }) - - - - - - 可自定义解析表达式 @@ -3346,12 +3233,6 @@ 超时 - - - 获取资源 - - - 使用完毕后,归还资源 @@ -3422,12 +3303,6 @@ 资源对象 - - - 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 - - 资源对象 - 归还对象给对象池的时候触发 @@ -4085,4 +3960,171 @@ + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 生成类似Mongodb的ObjectId有序、不重复Guid + + + + + + 插入数据 + + + + + + + 插入数据,传入实体 + + + + + + + + 插入数据,传入实体数组 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 插入或更新数据,此功能依赖数据库特性(低版本可能不支持),参考如下: + MySql 5.6+: on duplicate key update + PostgreSQL 9.4+: on conflict do update + SqlServer 2008+: merge into + Oracle 11+: merge into + Sqlite: replace into + 达梦: merge into + 人大金仓:on conflict do update + 神通:merge into + MsAccess:不支持 + 注意区别:FreeSql.Repository 仓储也有 InsertOrUpdate 方法(不依赖数据库特性) + + + + + + + 修改数据 + + + + + + + 修改数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 查询数据 + + + + + + + 查询数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 删除数据 + + + + + + + 删除数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 开启事务(不支持异步) + v1.5.0 关闭了线程事务超时自动提交的机制 + + 事务体 () => {} + + + + 开启事务(不支持异步) + v1.5.0 关闭了线程事务超时自动提交的机制 + + + 事务体 () => {} + + + + 数据库访问对象 + + + + + 所有拦截方法都在这里 + + + + + CodeFirst 模式开发相关方法 + + + + + DbFirst 模式开发相关方法 + + + + + 全局过滤设置,可默认附加为 Select/Update/Delete 条件 + + + diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index 5f6fb7ea..1050d677 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -41,7 +41,7 @@ namespace FreeSql.Internal field.Append(", ").Append(parent.DbField); if (index >= 0) field.Append(_common.FieldAsAlias($"as{++index}")); else if (index == ReadAnonymousFieldAsCsName && string.IsNullOrEmpty(parent.CsName) == false) field.Append(_common.FieldAsAlias(parent.CsName)); - if (parent.CsType == null) parent.CsType = exp.Type; + if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; case ExpressionType.Convert: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand, getSelectGroupingMapString, whereCascadeExpression, isAllDtoMap); case ExpressionType.Constant: @@ -61,7 +61,7 @@ namespace FreeSql.Internal field.Append(", ").Append(parent.DbField); if (index >= 0) field.Append(_common.FieldAsAlias($"as{++index}")); else if (index == ReadAnonymousFieldAsCsName && string.IsNullOrEmpty(parent.CsName) == false) field.Append(_common.FieldAsAlias(parent.CsName)); - if (parent.CsType == null) parent.CsType = exp.Type; + if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; case ExpressionType.Call: var callExp = exp as MethodCallExpression; @@ -79,7 +79,7 @@ namespace FreeSql.Internal field.Append(", ").Append(parent.DbField); if (index >= 0) field.Append(_common.FieldAsAlias($"as{++index}")); else if (index == ReadAnonymousFieldAsCsName && string.IsNullOrEmpty(parent.CsName) == false) field.Append(_common.FieldAsAlias(parent.CsName)); - if (parent.CsType == null) parent.CsType = exp.Type; + if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; case ExpressionType.Parameter: case ExpressionType.MemberAccess: @@ -265,7 +265,7 @@ namespace FreeSql.Internal field.Append(", ").Append(parent.DbField); if (index >= 0) field.Append(_common.FieldAsAlias($"as{++index}")); else if (index == ReadAnonymousFieldAsCsName && string.IsNullOrEmpty(parent.CsName) == false) field.Append(_common.FieldAsAlias(parent.CsName)); - if (parent.CsType == null) parent.CsType = exp.Type; + if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; } public object ReadAnonymous(ReadAnonymousTypeInfo parent, DbDataReader dr, ref int index, bool notRead, ReadAnonymousDbValueRef dbValue) diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index ef10b55a..922d1573 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -154,6 +154,8 @@ namespace FreeSql.Internal if (trycol.ServerTime != DateTimeKind.Unspecified) attr.ServerTime = trycol.ServerTime; if (trycol._StringLength != null) attr.StringLength = trycol.StringLength; if (!string.IsNullOrEmpty(trycol.InsertValueSql)) attr.InsertValueSql = trycol.InsertValueSql; + if (trycol._Precision != null) attr.Precision = trycol.Precision; + if (trycol._Scale != null) attr.Scale = trycol.Scale; } var attrs = proto.GetCustomAttributes(typeof(ColumnAttribute), false); foreach (var tryattrobj in attrs) @@ -174,7 +176,9 @@ namespace FreeSql.Internal if (tryattr._CanUpdate != null) attr._CanUpdate = tryattr.CanUpdate; if (tryattr.ServerTime != DateTimeKind.Unspecified) attr.ServerTime = tryattr.ServerTime; if (tryattr._StringLength != null) attr.StringLength = tryattr.StringLength; - if (!string.IsNullOrEmpty(tryattr.InsertValueSql)) attr.InsertValueSql = tryattr.InsertValueSql; + if (!string.IsNullOrEmpty(tryattr.InsertValueSql)) attr.InsertValueSql = tryattr.InsertValueSql; + if (tryattr._Precision != null) attr.Precision = tryattr.Precision; + if (tryattr._Scale != null) attr.Scale = tryattr.Scale; } ColumnAttribute ret = null; if (!string.IsNullOrEmpty(attr.Name)) ret = attr; diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index a499e1ff..98d6edeb 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -279,19 +279,19 @@ namespace FreeSql.Internal if (colattr.MapType == typeof(byte[]) && colattr.StringLength != 0) { int strlen = colattr.StringLength; - var charPatten = @"(VARBINARY|BINARY|BYTEA)\s*(\([^\)]*\))?"; + var bytePatten = @"(VARBINARY|BINARY|BYTEA)\s*(\([^\)]*\))?"; switch (common._orm.Ado.DataType) { case DataType.MySql: case DataType.OdbcMySql: if (strlen == -2) colattr.DbType = "LONGBLOB"; else if (strlen < 0) colattr.DbType = "BLOB"; - else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})"); + else colattr.DbType = Regex.Replace(colattr.DbType, bytePatten, $"$1({strlen})"); break; case DataType.SqlServer: case DataType.OdbcSqlServer: - if (strlen < 0) colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1(MAX)"); - else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})"); + if (strlen < 0) colattr.DbType = Regex.Replace(colattr.DbType, bytePatten, $"$1(MAX)"); + else colattr.DbType = Regex.Replace(colattr.DbType, bytePatten, $"$1({strlen})"); break; case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: @@ -314,10 +314,15 @@ namespace FreeSql.Internal break; case DataType.MsAccess: if (strlen < 0) colattr.DbType = "BLOB"; - else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})"); + else colattr.DbType = Regex.Replace(colattr.DbType, bytePatten, $"$1({strlen})"); break; } } + if (colattr.MapType == typeof(decimal) && colattr.Precision > 0) + { + var decimalPatten = @"(DECIMAL|NUMERIC|NUMBER)\s*(\([^\)]*\))?"; + colattr.DbType = Regex.Replace(colattr.DbType, decimalPatten, $"$1({colattr.Precision},{colattr.Scale})"); + } if (trytb.Columns.ContainsKey(colattr.Name)) throw new Exception($"ColumnAttribute.Name {colattr.Name} 重复存在,请检查(注意:不区分大小写)"); if (trytb.ColumnsByCs.ContainsKey(p.Name)) throw new Exception($"属性名 {p.Name} 重复存在,请检查(注意:不区分大小写)"); diff --git a/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerExpression.cs b/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerExpression.cs index ed2ef297..76f2ae6d 100644 --- a/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerExpression.cs +++ b/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerExpression.cs @@ -113,7 +113,7 @@ namespace FreeSql.Odbc.SqlServer { case "First": case "FirstOrDefault": - return $"substr({getExp(callExp.Arguments[0])}, 1, 1)"; + return $"substring({getExp(callExp.Arguments[0])}, 1, 1)"; } } }