From c78c4ed7ae399808ea8f6117f51901d5498e7dab Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 22 Apr 2020 14:37:30 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E4=BF=AE=E5=A4=8D=20=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E4=B8=BA=20char=20=E6=97=B6=20ExpressionTree?= =?UTF-8?q?=20=E8=AF=BB=E5=8F=96=E5=A4=B1=E8=B4=A5=20bug=EF=BC=9B#283=20-?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=20=E8=A1=A8=E8=BE=BE=E5=BC=8F=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=20Include=20=E7=88=B6=E5=AD=90=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E5=A4=B1=E8=B4=A5=E7=9A=84=20bug=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.DbContext/FreeSql.DbContext.xml | 16 ++ .../BankOutlets.cs | 75 +++++++ .../Banks.cs | 66 ++++++ .../UnitTest1.cs | 5 + FreeSql.Tests/FreeSql.Tests/Issues/283.cs | 196 ++++++++++++++++++ .../SelectProvider/Select1Provider.cs | 1 + FreeSql/Internal/UtilsExpressionTree.cs | 45 ++-- 7 files changed, 382 insertions(+), 22 deletions(-) create mode 100644 FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/BankOutlets.cs create mode 100644 FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/Banks.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/Issues/283.cs diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 2c69043d..9f17feac 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -120,6 +120,13 @@ 清空状态数据 + + + 根据 lambda 条件删除数据 + + + + 添加 @@ -450,5 +457,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/BankOutlets.cs b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/BankOutlets.cs new file mode 100644 index 00000000..25ab8b30 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/BankOutlets.cs @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具 FreeSql.Generator 生成。 +// 运行时版本:3.1.0 +// Website: https://github.com/2881099/FreeSql +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using FreeSql.DataAnnotations; +namespace FreeSql.Jhfw.Models { + + public interface IBaseModel + { + TKey Id { get; set; } + } + [JsonObject(MemberSerialization.OptIn), Table(Name = "bank_outlets")] + public partial class BankOutlets : IBaseModel + { + + [JsonProperty] + public int? BankId { get => _BankId; set { + if (_BankId == value) return; + _BankId = value; + OneBanks = null; + }} + private int? _BankId; + + [JsonProperty] + public int? ParentId { get => _ParentId; set { + if (_ParentId == value) return; + _ParentId = value; + OneBankOutlets = null; + }} + private int? _ParentId; + + [JsonProperty] + public string Address { get; set; } = ""; + + [JsonProperty, Column(DbType = "varchar(50)")] + public string Area { get; set; } = ""; + + [JsonProperty, Column(Name = "ID", IsIdentity = true)] + public int Id { get; set; } + + [JsonProperty, Column(DbType = "varchar(50)")] + public string Name { get; set; } = ""; + + + #region 外键 => 导航属性,ManyToOne/OneToOne + + [Navigate("BankId")] + public virtual Banks OneBanks { get; set; } + + [Navigate("ParentId")] + public virtual BankOutlets OneBankOutlets { get; set; } + + #endregion + + #region 外键 => 导航属性,OneToMany + + [Navigate("ParentId")] + public virtual List ManyBankOutlets { get; set; } + + #endregion + + #region 外键 => 导航属性,ManyToMany + + #endregion + } + +} diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/Banks.cs b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/Banks.cs new file mode 100644 index 00000000..17f26cdb --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/Banks.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具 FreeSql.Generator 生成。 +// 运行时版本:3.1.0 +// Website: https://github.com/2881099/FreeSql +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using FreeSql.DataAnnotations; +namespace FreeSql.Jhfw.Models { + + [JsonObject(MemberSerialization.OptIn), Table(Name = "banks")] + public partial class Banks : IBaseModel + { + + [JsonProperty, Column(DbType = "datetime")] + public DateTime? Addtime { get; set; } + + [JsonProperty, Column(DbType = "varchar(250)")] + public string Banner { get; set; } = ""; + + [JsonProperty, Column(DbType = "varchar(20)")] + public string City { get; set; } = ""; + + [JsonProperty, Column(Name = "ID", IsIdentity = true)] + public int Id { get; set; } + + [JsonProperty, Column(DbType = "tinyint(1)")] + public bool IsDelete { get; set; } + + [JsonProperty, Column(DbType = "tinyint(1)")] + public bool IsGrab { get; set; } + + [JsonProperty, Column(DbType = "tinyint(1)")] + public bool IsJoinHmd { get; set; } + + [JsonProperty, Column(DbType = "varchar(100)")] + public string LoanType { get; set; } = ""; + + [JsonProperty, Column(DbType = "varchar(250)")] + public string Logo { get; set; } = ""; + + [JsonProperty] + public string Name { get; set; } = ""; + + [JsonProperty, Column(DbType = "varchar(3000)")] + public string Notice { get; set; } = ""; + + + #region 外键 => 导航属性,OneToMany + + [Navigate("BankId")] + public virtual List ManyBankOutlets { get; set; } + + #endregion + + #region 外键 => 导航属性,ManyToMany + + #endregion + } + +} diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/UnitTest1.cs b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/UnitTest1.cs index d3300f9b..fa20bfdd 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/UnitTest1.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/UnitTest1.cs @@ -32,6 +32,11 @@ namespace FreeSql.Tests.MySqlConnector public void Test1() { g.mysql.Select().ToList(); + + + var soc = g.mysql.GetRepository(); + var item1 = soc.Where(d => d.Id == 1).Include(x => x.OneBankOutlets).Include(d => d.OneBanks).First(); + var item2 = soc.Where(d => d.Id == 1).Include(d => d.OneBanks).Include(x => x.OneBankOutlets).First(); } } } diff --git a/FreeSql.Tests/FreeSql.Tests/Issues/283.cs b/FreeSql.Tests/FreeSql.Tests/Issues/283.cs new file mode 100644 index 00000000..1fd3ecf1 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/Issues/283.cs @@ -0,0 +1,196 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace FreeSql.Tests.Issues +{ + public class _283 + { + [Fact] + public void SelectTest() + { + IFreeSql db = g.sqlserver; + + db.Transaction(() => + { + db.Delete().Where("1=1").ExecuteAffrows(); + db.Delete().Where("1=1").ExecuteAffrows(); + + var dictionaries = new BuildDictionary[] + { + new BuildDictionary { Type = 1, Code = 'A', Name = "办公建筑" }, + new BuildDictionary { Type = 1, Code = 'B', Name = "商场建筑" }, + new BuildDictionary { Type = 1, Code = 'C', Name = "宾馆饭店建筑" }, + new BuildDictionary { Type = 1, Code = 'D', Name = "文化教育建筑" }, + new BuildDictionary { Type = 1, Code = 'E', Name = "医疗卫生建筑" }, + new BuildDictionary { Type = 1, Code = 'F', Name = "体育建筑" }, + new BuildDictionary { Type = 1, Code = 'G', Name = "综合建筑" }, + new BuildDictionary { Type = 1, Code = 'Z', Name = "其他建筑" }, + + new BuildDictionary { Type = 2, Code = 'A', Name = "结构建筑" }, + new BuildDictionary { Type = 2, Code = 'B', Name = "框剪结构" }, + new BuildDictionary { Type = 2, Code = 'C', Name = "剪力墙结构" }, + new BuildDictionary { Type = 2, Code = 'D', Name = "砖混结构" }, + new BuildDictionary { Type = 2, Code = 'E', Name = "钢结构" }, + new BuildDictionary { Type = 2, Code = 'F', Name = "筒体结构" }, + new BuildDictionary { Type = 2, Code = 'G', Name = "木结构" }, + new BuildDictionary { Type = 2, Code = 'Z', Name = "其他" }, + + new BuildDictionary { Type = 3, Code = 'A', Name = "集中式全空气系统" }, + new BuildDictionary { Type = 3, Code = 'B', Name = "风机盘管+新风系统" }, + new BuildDictionary { Type = 3, Code = 'C', Name = "分体式空调或 VRV 的局部式机组系统" }, + new BuildDictionary { Type = 3, Code = 'Z', Name = "其他" }, + + new BuildDictionary { Type = 4, Code = 'A', Name = "散热器采暖" }, + new BuildDictionary { Type = 4, Code = 'B', Name = "地板辐射采暖" }, + new BuildDictionary { Type = 4, Code = 'C', Name = "电辐射采暖" }, + new BuildDictionary { Type = 4, Code = 'D', Name = "空调系统集中供暖" }, + new BuildDictionary { Type = 4, Code = 'Z', Name = "其他" }, + + new BuildDictionary { Type = 5, Code = 'A', Name = "砖" }, + new BuildDictionary { Type = 5, Code = 'B', Name = "建筑砌块" }, + new BuildDictionary { Type = 5, Code = 'C', Name = "板材墙体" }, + new BuildDictionary { Type = 5, Code = 'D', Name = "复合墙板和墙体" }, + new BuildDictionary { Type = 5, Code = 'E', Name = "玻璃幕墙" }, + new BuildDictionary { Type = 5, Code = 'Z', Name = "其他" }, + + new BuildDictionary { Type = 6, Code = 'A', Name = "内保温" }, + new BuildDictionary { Type = 6, Code = 'B', Name = "外保温" }, + new BuildDictionary { Type = 6, Code = 'C', Name = "夹芯保温" }, + new BuildDictionary { Type = 6, Code = 'Z', Name = "其他" }, + + new BuildDictionary { Type = 7, Code = 'A', Name = "单玻单层窗" }, + new BuildDictionary { Type = 7, Code = 'B', Name = "单玻双层窗" }, + new BuildDictionary { Type = 7, Code = 'C', Name = "单玻单层窗+单玻双层窗" }, + new BuildDictionary { Type = 7, Code = 'D', Name = "中空双层玻璃窗" }, + new BuildDictionary { Type = 7, Code = 'E', Name = "中空三层玻璃窗" }, + new BuildDictionary { Type = 7, Code = 'F', Name = "中空充惰性气体" }, + new BuildDictionary { Type = 7, Code = 'Z', Name = "其他" }, + + new BuildDictionary { Type = 8, Code = 'A', Name = "普通玻璃" }, + new BuildDictionary { Type = 8, Code = 'B', Name = "镀膜玻璃" }, + new BuildDictionary { Type = 8, Code = 'C', Name = "Low-e 玻璃" }, + new BuildDictionary { Type = 8, Code = 'Z', Name = "其他" }, + + new BuildDictionary { Type = 9, Code = 'A', Name = "钢窗" }, + new BuildDictionary { Type = 9, Code = 'B', Name = "铝合金" }, + new BuildDictionary { Type = 9, Code = 'C', Name = "木窗" }, + new BuildDictionary { Type = 9, Code = 'D', Name = "断热窗框" }, + new BuildDictionary { Type = 9, Code = 'E', Name = "塑钢" }, + new BuildDictionary { Type = 9, Code = 'Z', Name = "其他" }, + }; + + db.Insert(dictionaries).ExecuteAffrows(); + + Build2 build = new Build2 + { + ID = 1, + Name = "建筑 1", + BuildFunctionCode = 'A', + BuildStructureCode = 'A', + AirTypeCode = 'A', + HeatTypeCode = 'A', + WallMaterialTypeCode = 'A', + WallWarmTypeCode = 'A', + WallWindowsTypeCode = 'A', + GlassTypeCode = 'A', + WinFrameMaterialCode = 'A' + }; + + db.Insert(build).ExecuteAffrows(); + }); + + Build2 build = db.Select() + .InnerJoin(a => a.BuildFunctionCode == a.BuildFunction.Code && a.BuildFunction.Type == 1) + .InnerJoin(a => a.BuildStructureCode == a.BuildStructure.Code && a.BuildStructure.Type == 2) + .InnerJoin(a => a.AirTypeCode == a.AirType.Code && a.AirType.Type == 3) + .InnerJoin(a => a.HeatTypeCode == a.HeatType.Code && a.HeatType.Type == 4) + .InnerJoin(a => a.WallMaterialTypeCode == a.WallMaterialType.Code && a.WallMaterialType.Type == 5) + .InnerJoin(a => a.WallWarmTypeCode == a.WallWarmType.Code && a.WallWarmType.Type == 6) + .InnerJoin(a => a.WallWindowsTypeCode == a.WallWindowsType.Code && a.WallWindowsType.Type == 7) + .InnerJoin(a => a.GlassTypeCode == a.GlassType.Code && a.GlassType.Type == 8) + .InnerJoin(a => a.WinFrameMaterialCode == a.WinFrameMaterial.Code && a.WinFrameMaterial.Type == 9) + .Where(a => a.ID == 1) + .ToOne(); + + Assert.NotNull(build); + } + + [Table(Name = "F_Build2")] + public class Build2 + { + public int ID { get; set; } + + public string Name { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char BuildFunctionCode { get; set; } + + [Navigate(nameof(BuildFunctionCode))] + public BuildDictionary BuildFunction { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char BuildStructureCode { get; set; } + + [Navigate(nameof(BuildStructureCode))] + public BuildDictionary BuildStructure { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char AirTypeCode { get; set; } + + [Navigate(nameof(AirTypeCode))] + public BuildDictionary AirType { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char HeatTypeCode { get; set; } + + [Navigate(nameof(HeatTypeCode))] + public BuildDictionary HeatType { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char WallMaterialTypeCode { get; set; } + + [Navigate(nameof(WallMaterialTypeCode))] + public BuildDictionary WallMaterialType { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char WallWarmTypeCode { get; set; } + + [Navigate(nameof(WallWarmTypeCode))] + public BuildDictionary WallWarmType { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char WallWindowsTypeCode { get; set; } + + [Navigate(nameof(WallWindowsTypeCode))] + public BuildDictionary WallWindowsType { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char GlassTypeCode { get; set; } + + [Navigate(nameof(GlassTypeCode))] + public BuildDictionary GlassType { get; set; } + + [Column(MapType = typeof(string), DbType = "char")] + public char WinFrameMaterialCode { get; set; } + + [Navigate(nameof(WinFrameMaterialCode))] + public BuildDictionary WinFrameMaterial { get; set; } + } + + [Table(Name = "F_BuildDictionary")] + public class BuildDictionary + { + [Column(IsPrimary = true)] + public int Type { get; set; } + + [Column(IsPrimary = true, MapType = typeof(string), DbType = "char")] + public char Code { get; set; } + + [Column(StringLength = 20, IsNullable = false)] + public string Name { get; set; } + } + } +} diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index 48714a49..3870966f 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -287,6 +287,7 @@ namespace FreeSql.Internal.CommonProvider if (tb == null) throw new Exception("Include 参数类型错误"); _isIncluded = true; + _tables[0].Parameter = navigateSelector.Parameters[0]; _commonExpression.ExpressionWhereLambda(_tables, Expression.MakeMemberAccess(expBody, tb.Properties[tb.ColumnsByCs.First().Value.CsName]), null, null, null); return this; } diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 98f4a128..5ea91584 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -1236,6 +1236,7 @@ namespace FreeSql.Internal public static PropertyInfo PropertyDataIndex = typeof(RowInfo).GetProperty("DataIndex"); } internal static MethodInfo MethodDataReaderGetValue = typeof(Utils).GetMethod("InternalDataReaderGetValue", BindingFlags.Static | BindingFlags.NonPublic); + internal static PropertyInfo PropertyDataReaderFieldCount = typeof(DbDataReader).GetProperty("FieldCount"); internal static object InternalDataReaderGetValue(CommonUtils commonUtil, DbDataReader dr, int index) { if (commonUtil._orm.Ado.DataType == DataType.Dameng && dr.IsDBNull(index)) return null; @@ -1309,33 +1310,33 @@ namespace FreeSql.Internal } } block2Exp.AddRange(new Expression[] { - //Expression.TryCatch(Expression.Block( - // typeof(void), - Expression.Assign(read2Exp, read2ExpAssign), - Expression.IfThen(Expression.GreaterThan(read2ExpDataIndex, dataIndexExp), - Expression.Assign(dataIndexExp, read2ExpDataIndex)), - Expression.IfThenElse(Expression.Equal(read2ExpValue, Expression.Constant(null)), - Expression.Assign(Expression.MakeMemberAccess(ret2Exp, field), Expression.Default(field.FieldType)), - Expression.Assign(Expression.MakeMemberAccess(ret2Exp, field), Expression.Convert(read2ExpValue, field.FieldType))) - //), - //Expression.Catch(typeof(Exception), Expression.Block( - // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(0)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 0)))), - // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(1)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 1)))), - // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(2)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 2)))), - // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(3)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 3)))), - // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(4)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 4)))) - // ) - //)) - }); + //Expression.TryCatch(Expression.Block( + // typeof(void), + Expression.Assign(read2Exp, read2ExpAssign), + Expression.IfThen(Expression.GreaterThan(read2ExpDataIndex, dataIndexExp), + Expression.Assign(dataIndexExp, read2ExpDataIndex)), + Expression.IfThenElse(Expression.Equal(read2ExpValue, Expression.Constant(null)), + Expression.Assign(Expression.MakeMemberAccess(ret2Exp, field), Expression.Default(field.FieldType)), + Expression.Assign(Expression.MakeMemberAccess(ret2Exp, field), Expression.Convert(read2ExpValue, field.FieldType))) + //), + //Expression.Catch(typeof(Exception), Expression.Block( + // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(0)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 0)))), + // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(1)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 1)))), + // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(2)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 2)))), + // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(3)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 3)))), + // Expression.IfThen(Expression.Equal(read2ExpDataIndex, Expression.Constant(4)), Expression.Throw(Expression.Constant(new Exception(field.Name + "," + 4)))) + // ) + //)) + }); } block2Exp.AddRange(new Expression[] { - Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, Expression.Convert(ret2Exp, typeof(object)), dataIndexExp)), - Expression.Label(returnTarget, Expression.Default(typeof(RowInfo))) - }); + Expression.Return(returnTarget, Expression.New(RowInfo.Constructor, Expression.Convert(ret2Exp, typeof(object)), dataIndexExp)), + Expression.Label(returnTarget, Expression.Default(typeof(RowInfo))) + }); return Expression.Lambda>( Expression.Block(new[] { ret2Exp, read2Exp }, block2Exp), new[] { typeExp, indexesExp, rowExp, dataIndexExp, commonUtilExp }).Compile(); } - var rowLenExp = Expression.ArrayLength(rowExp); + var rowLenExp = Expression.MakeMemberAccess(rowExp, PropertyDataReaderFieldCount); return Expression.Lambda>( Expression.Block( Expression.IfThen(