From 960da5a2c2560b5c4cb926cdc17fae31d5391e6e Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Mon, 21 Dec 2020 23:35:56 +0800 Subject: [PATCH] test RereadSql/RewriteSql #614 --- .../SqlServer/SqlServerCodeFirstTest.cs | 211 ++++++++++++++++++ FreeSql/DataAnnotations/ColumnFluent.cs | 26 +++ FreeSql/FreeSql.xml | 19 ++ FreeSql/Internal/CommonExpression.cs | 15 +- .../Internal/CommonProvider/UpdateProvider.cs | 4 +- FreeSql/Internal/CommonUtils.cs | 8 +- FreeSql/Internal/Model/TableInfo.cs | 1 + FreeSql/Internal/UtilsExpressionTree.cs | 1 + 8 files changed, 277 insertions(+), 8 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs index 5099b8ef..9144f224 100644 --- a/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs @@ -12,6 +12,217 @@ namespace FreeSql.Tests.SqlServer { public class SqlServerCodeFirstTest { + [Fact] + public void GeographyCrud() + { + var fsql = g.sqlserver; + fsql.Delete().Where("1=1").ExecuteAffrows(); + var id1 = Guid.NewGuid(); + var geo1 = "LINESTRING (-122.36 47.656, -122.343 47.656)"; + Assert.Equal(1, fsql.Insert(new ts_geocrud01 { id = id1, geo = geo1 }).ExecuteAffrows()); + var item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + //NoneParameter + fsql.Delete().Where("1=1").ExecuteAffrows(); + id1 = Guid.NewGuid(); + geo1 = "LINESTRING (-122.36 47.656, -122.343 47.656)"; + Assert.Equal(1, fsql.Insert(new ts_geocrud01 { id = id1, geo = geo1 }).NoneParameter().ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + var item2 = fsql.Select().Where(a => a.id == id1).First(a => a.geo); + Assert.Equal(geo1, item2); + var item3 = fsql.Select().Where(a => a.id == id1).First(a => new { a.geo }); + Assert.Equal(geo1, item3.geo); + var item4 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocrud01 { geo = a.geo }); + Assert.Equal(geo1, item4.geo); + var item5 = fsql.Select().Where(a => a.id == id1).ToList().FirstOrDefault(); + Assert.Equal(geo1, item5.geo); + var item6 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocurd01_dto1 { geo = a.geo }); + Assert.Equal(geo1, item6.geo); + + //Update SetSource + geo1 = "COMPOUNDCURVE (CIRCULARSTRING (-122.358 47.653, -122.348 47.649, -122.348 47.658), CIRCULARSTRING (-122.348 47.658, -122.358 47.658, -122.358 47.653))"; + item1.geo = geo1; + Assert.Equal(1, fsql.Update().SetSource(item1).ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + item2 = fsql.Select().Where(a => a.id == id1).First(a => a.geo); + Assert.Equal(geo1, item2); + item3 = fsql.Select().Where(a => a.id == id1).First(a => new { a.geo }); + Assert.Equal(geo1, item3.geo); + item4 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocrud01 { geo = a.geo }); + Assert.Equal(geo1, item4.geo); + item5 = fsql.Select().Where(a => a.id == id1).ToList().FirstOrDefault(); + Assert.Equal(geo1, item5.geo); + item6 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocurd01_dto1 { geo = a.geo }); + Assert.Equal(geo1, item6.geo); + + //Update SetSource NoneParameter + geo1 = "COMPOUNDCURVE (CIRCULARSTRING (-122.358 47.653, -122.348 47.649, -122.348 47.658), CIRCULARSTRING (-122.348 47.658, -122.358 47.658, -122.358 47.653))"; + item1.geo = geo1; + Assert.Equal(1, fsql.Update().SetSource(item1).NoneParameter().ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + item2 = fsql.Select().Where(a => a.id == id1).First(a => a.geo); + Assert.Equal(geo1, item2); + item3 = fsql.Select().Where(a => a.id == id1).First(a => new { a.geo }); + Assert.Equal(geo1, item3.geo); + item4 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocrud01 { geo = a.geo }); + Assert.Equal(geo1, item4.geo); + item5 = fsql.Select().Where(a => a.id == id1).ToList().FirstOrDefault(); + Assert.Equal(geo1, item5.geo); + item6 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocurd01_dto1 { geo = a.geo }); + Assert.Equal(geo1, item6.geo); + + //Update Set + geo1 = "POLYGON ((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))"; + Assert.Equal(1, fsql.Update().Where(a => a.id == id1).Set(a => a.geo, geo1).ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + item2 = fsql.Select().Where(a => a.id == id1).First(a => a.geo); + Assert.Equal(geo1, item2); + item3 = fsql.Select().Where(a => a.id == id1).First(a => new { a.geo }); + Assert.Equal(geo1, item3.geo); + item4 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocrud01 { geo = a.geo }); + Assert.Equal(geo1, item4.geo); + item5 = fsql.Select().Where(a => a.id == id1).ToList().FirstOrDefault(); + Assert.Equal(geo1, item5.geo); + item6 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocurd01_dto1 { geo = a.geo }); + Assert.Equal(geo1, item6.geo); + + //Update Set NoneParameter + geo1 = "POLYGON ((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))"; + Assert.Equal(1, fsql.Update().NoneParameter().Where(a => a.id == id1).Set(a => a.geo, geo1).ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + item2 = fsql.Select().Where(a => a.id == id1).First(a => a.geo); + Assert.Equal(geo1, item2); + item3 = fsql.Select().Where(a => a.id == id1).First(a => new { a.geo }); + Assert.Equal(geo1, item3.geo); + item4 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocrud01 { geo = a.geo }); + Assert.Equal(geo1, item4.geo); + item5 = fsql.Select().Where(a => a.id == id1).ToList().FirstOrDefault(); + Assert.Equal(geo1, item5.geo); + item6 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocurd01_dto1 { geo = a.geo }); + Assert.Equal(geo1, item6.geo); + + //Update Set Multi + geo1 = "LINESTRING (-122.36 47.656, -122.343 47.656)"; + Assert.Equal(1, fsql.Update().Where(a => a.id == id1).Set(a => new + { + geo = geo1 + }).ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + item2 = fsql.Select().Where(a => a.id == id1).First(a => a.geo); + Assert.Equal(geo1, item2); + item3 = fsql.Select().Where(a => a.id == id1).First(a => new { a.geo }); + Assert.Equal(geo1, item3.geo); + item4 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocrud01 { geo = a.geo }); + Assert.Equal(geo1, item4.geo); + item5 = fsql.Select().Where(a => a.id == id1).ToList().FirstOrDefault(); + Assert.Equal(geo1, item5.geo); + item6 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocurd01_dto1 { geo = a.geo }); + Assert.Equal(geo1, item6.geo); + + //Update Set Multi NoneParameter + geo1 = "LINESTRING (-122.36 47.656, -122.343 47.656)"; + Assert.Equal(1, fsql.Update().NoneParameter().Where(a => a.id == id1).Set(a => new + { + geo = geo1 + }).ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == id1).First(); + Assert.NotNull(item1); + Assert.Equal(id1, item1.id); + Assert.Equal(geo1, item1.geo); + + item2 = fsql.Select().Where(a => a.id == id1).First(a => a.geo); + Assert.Equal(geo1, item2); + item3 = fsql.Select().Where(a => a.id == id1).First(a => new { a.geo }); + Assert.Equal(geo1, item3.geo); + item4 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocrud01 { geo = a.geo }); + Assert.Equal(geo1, item4.geo); + item5 = fsql.Select().Where(a => a.id == id1).ToList().FirstOrDefault(); + Assert.Equal(geo1, item5.geo); + item6 = fsql.Select().Where(a => a.id == id1).First(a => new ts_geocurd01_dto1 { geo = a.geo }); + Assert.Equal(geo1, item6.geo); + + // + fsql.Delete().Where("1=1").ExecuteAffrows(); + id1 = Guid.NewGuid(); + geo1 = "LINESTRING (-122.36 47.656, -122.343 47.656)"; + var id2 = Guid.NewGuid(); + var geo2 = "POLYGON ((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))"; + Assert.Equal(2, fsql.Insert(new[] { new ts_geocrud01 { id = id1, geo = geo1 }, new ts_geocrud01 { id = id2, geo = geo2 } }).ExecuteAffrows()); + var items = fsql.Select().ToList(); + Assert.Equal(2, items.Count); + + items[0].geo = "POLYGON EMPTY"; + items[1].geo = "LINESTRING (0 0, 2 2, 1 0)"; + Assert.Equal(2, fsql.Update().SetSource(items).ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == items[0].id).First(); + Assert.NotNull(item1); + Assert.Equal(items[0].id, item1.id); + Assert.Equal(items[0].geo, item1.geo); + item1 = fsql.Select().Where(a => a.id == items[1].id).First(); + Assert.NotNull(item1); + Assert.Equal(items[1].id, item1.id); + Assert.Equal(items[1].geo, item1.geo); + + // NoneParameter + fsql.Delete().Where("1=1").ExecuteAffrows(); + id1 = Guid.NewGuid(); + geo1 = "LINESTRING (-122.36 47.656, -122.343 47.656)"; + id2 = Guid.NewGuid(); + geo2 = "POLYGON ((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))"; + Assert.Equal(2, fsql.Insert(new[] { new ts_geocrud01 { id = id1, geo = geo1 }, new ts_geocrud01 { id = id2, geo = geo2 } }).NoneParameter().ExecuteAffrows()); + items = fsql.Select().ToList(); + Assert.Equal(2, items.Count); + + items[0].geo = "POLYGON EMPTY"; + items[1].geo = "LINESTRING (0 0, 2 2, 1 0)"; + Assert.Equal(2, fsql.Update().NoneParameter().SetSource(items).ExecuteAffrows()); + item1 = fsql.Select().Where(a => a.id == items[0].id).First(); + Assert.NotNull(item1); + Assert.Equal(items[0].id, item1.id); + Assert.Equal(items[0].geo, item1.geo); + item1 = fsql.Select().Where(a => a.id == items[1].id).First(); + Assert.NotNull(item1); + Assert.Equal(items[1].id, item1.id); + Assert.Equal(items[1].geo, item1.geo); + } + class ts_geocrud01 + { + public Guid id { get; set; } + [Column(DbType = "geography", RewriteSql = "geography::STGeomFromText({0},4236)", RereadSql = "{0}.STAsText()")] + public string geo { get; set; } + } + class ts_geocurd01_dto1 + { + public string geo { get; set; } + } + [Fact] public void InsertUpdateParameter() { diff --git a/FreeSql/DataAnnotations/ColumnFluent.cs b/FreeSql/DataAnnotations/ColumnFluent.cs index 4b5b1e09..47de1150 100644 --- a/FreeSql/DataAnnotations/ColumnFluent.cs +++ b/FreeSql/DataAnnotations/ColumnFluent.cs @@ -189,5 +189,31 @@ namespace FreeSql.DataAnnotations _column.Scale = scale; return this; } + + /// + /// 重写功能 + /// 比如:[Column(RewriteSql = "geography::STGeomFromText({0},4236)")] + /// 插入:INSERT INTO [table]([geo]) VALUES(geography::STGeomFromText('...',4236)) + /// 提示:更新也生效 + /// + /// + /// + public ColumnFluent RewriteSql(string value) + { + _column.RewriteSql = value; + return this; + } + /// + /// 重读功能 + /// 比如:[Column(RereadSql = "{0}.STAsText()")] + /// 查询:SELECT a.[id], a.[geo].STAsText() FROM [table] a + /// + /// + /// + public ColumnFluent RereadSql(string value) + { + _column.RereadSql = value; + return this; + } } } diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 6459ce6a..a03e244a 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -246,6 +246,25 @@ 小数位长度 + + + 重写功能 + 比如:[Column(RewriteSql = "geography::STGeomFromText({0},4236)")] + 插入:INSERT INTO [table]([geo]) VALUES(geography::STGeomFromText('...',4236)) + 提示:更新也生效 + + + + + + + 重读功能 + 比如:[Column(RereadSql = "{0}.STAsText()")] + 查询:SELECT a.[id], a.[geo].STAsText() FROM [table] a + + + + 自定义表达式函数解析 diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index 98fb91de..103fefa8 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -195,8 +195,14 @@ namespace FreeSql.Internal return false; } if (parent.CsType == null) parent.CsType = exp.Type; - parent.DbField = ExpressionLambdaToSql(exp, getTSC()); - field.Append(", ").Append(parent.DbField); + var pdbfield = parent.DbField = ExpressionLambdaToSql(exp, getTSC()); + if (parent.MapType == null || _tables?.Any(a => a.Table.IsRereadSql) == true) + { + var findcol = SearchColumnByField(_tables, null, parent.DbField); + if (parent.MapType == null) parent.MapType = findcol?.Attribute.MapType ?? exp.Type; + if (findcol != null) pdbfield = _common.RereadColumn(findcol, pdbfield); + } + field.Append(", ").Append(pdbfield); if (index >= 0) field.Append(_common.FieldAsAlias($"as{++index}")); else if (index == ReadAnonymousFieldAsCsName && string.IsNullOrEmpty(parent.CsName) == false) { @@ -204,7 +210,6 @@ namespace FreeSql.Internal if (parent.DbField.EndsWith(csname, StringComparison.CurrentCultureIgnoreCase) == false) //DbField 和 CsName 相同的时候,不处理 field.Append(_common.FieldAsAlias(csname)); } - if (parent.MapType == null) parent.MapType = SearchColumnByField(_tables, null, parent.DbField)?.Attribute.MapType ?? exp.Type; return false; } return false; @@ -254,7 +259,7 @@ namespace FreeSql.Internal else { child.DbField = $"{dtTb.Alias}.{_common.QuoteSqlName(trydtocol.Attribute.Name)}"; - field.Append(", ").Append(child.DbField); + field.Append(", ").Append(_common.RereadColumn(trydtocol, child.DbField)); if (index >= 0) field.Append(_common.FieldAsAlias($"as{++index}")); } break; @@ -336,7 +341,7 @@ namespace FreeSql.Internal ReadAnonymousField(_tables, field, child, ref index, Expression.Property(dtTb.Parameter, dtTb.Table.Properties[trydtocol.CsName]), select, diymemexp, whereGlobalFilter, findIncludeMany, isAllDtoMap); else { - child.DbField = $"{dtTb.Alias}.{_common.QuoteSqlName(trydtocol.Attribute.Name)}"; + child.DbField = _common.RereadColumn(trydtocol, $"{dtTb.Alias}.{_common.QuoteSqlName(trydtocol.Attribute.Name)}"); field.Append(", ").Append(child.DbField); if (index >= 0) field.Append(_common.FieldAsAlias($"as{++index}")); } diff --git a/FreeSql/Internal/CommonProvider/UpdateProvider.cs b/FreeSql/Internal/CommonProvider/UpdateProvider.cs index 8b6f478a..8f5044fd 100644 --- a/FreeSql/Internal/CommonProvider/UpdateProvider.cs +++ b/FreeSql/Internal/CommonProvider/UpdateProvider.cs @@ -698,7 +698,7 @@ namespace FreeSql.Internal.CommonProvider var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(_paramsSource, "u", col, col.Attribute.MapType, val) : _commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}")); - _set.Append(_commonUtils.RewriteColumn(col, colsql)); + sb.Append(_commonUtils.RewriteColumn(col, colsql)); if (_noneParameter == false) _commonUtils.AppendParamter(_paramsSource, null, col, col.Attribute.MapType, val); } @@ -742,7 +742,7 @@ namespace FreeSql.Internal.CommonProvider var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(_paramsSource, "u", col, col.Attribute.MapType, val) : _commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}")); - _set.Append(_commonUtils.RewriteColumn(col, colsql)); + cwsb.Append(_commonUtils.RewriteColumn(col, colsql)); if (_noneParameter == false) _commonUtils.AppendParamter(_paramsSource, null, col, col.Attribute.MapType, val); if (val == null || val == DBNull.Value) nulls++; diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index 4e152a38..a7fa8257 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -57,7 +57,7 @@ namespace FreeSql.Internal public string RewriteColumn(ColumnInfo col, string sql) { if (string.IsNullOrWhiteSpace(col?.Attribute.RewriteSql) == false) - return string.Format(col.Attribute.RereadSql, sql); + return string.Format(col.Attribute.RewriteSql, sql); return sql; } public string RereadColumn(ColumnInfo col, string columnName) @@ -170,6 +170,8 @@ namespace FreeSql.Internal 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; + if (!string.IsNullOrEmpty(trycol.RewriteSql)) attr.RewriteSql = trycol.RewriteSql; + if (!string.IsNullOrEmpty(trycol.RereadSql)) attr.RereadSql = trycol.RereadSql; } var attrs = proto.GetCustomAttributes(typeof(ColumnAttribute), false); foreach (var tryattrobj in attrs) @@ -193,6 +195,8 @@ namespace FreeSql.Internal 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; + if (!string.IsNullOrEmpty(tryattr.RewriteSql)) attr.RewriteSql = tryattr.RewriteSql; + if (!string.IsNullOrEmpty(tryattr.RereadSql)) attr.RereadSql = tryattr.RereadSql; } ColumnAttribute ret = null; if (!string.IsNullOrEmpty(attr.Name)) ret = attr; @@ -212,6 +216,8 @@ namespace FreeSql.Internal if (!string.IsNullOrEmpty(attr.InsertValueSql)) ret = attr; if (attr._Precision != null) ret = attr; if (attr._Scale != null) ret = attr; + if (!string.IsNullOrEmpty(attr.RewriteSql)) ret = attr; + if (!string.IsNullOrEmpty(attr.RereadSql)) ret = attr; if (ret != null && ret.MapType == null) ret.MapType = proto.PropertyType; return ret; } diff --git a/FreeSql/Internal/Model/TableInfo.cs b/FreeSql/Internal/Model/TableInfo.cs index c882cc72..0f68c2d4 100644 --- a/FreeSql/Internal/Model/TableInfo.cs +++ b/FreeSql/Internal/Model/TableInfo.cs @@ -23,6 +23,7 @@ namespace FreeSql.Internal.Model public string DbOldName { get; set; } public bool DisableSyncStructure { get; set; } public string Comment { get; internal set; } + public bool IsRereadSql { get; internal set; } public ColumnInfo VersionColumn { get; set; } diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 7313bcbd..9e570b04 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -495,6 +495,7 @@ namespace FreeSql.Internal col.DbPrecision = (byte)size; col.DbScale = scale; } + trytb.IsRereadSql = trytb.Columns.Where(a => string.IsNullOrWhiteSpace(a.Value.Attribute.RereadSql) == false).Any(); tbc.AddOrUpdate(entity, trytb, (oldkey, oldval) => trytb); #region 查找导航属性的关系、virtual 属性延时加载,动态产生新的重写类