diff --git a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs index df3d3c0a..546a102b 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs @@ -136,8 +136,20 @@ namespace FreeSql.Tests.MySql { var dt2 = select.Limit(10).ToDataTable("id, 111222"); var dt3 = select.Limit(10).ToDataTable(a => new { a.Id, a.Type.Name, now = DateTime.Now }); } + + class TestDto { + public int id { get; set; } + public string name { get; set; } + } [Fact] public void ToList() { + + var testDto1 = select.Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title }); + var testDto2 = select.Limit(10).ToList(a => new TestDto()); + var testDto3 = select.Limit(10).ToList(a => new TestDto { }); + var testDto4 = select.Limit(10).ToList(a => new TestDto() { }); + + var t0 = select.Limit(50).ToList(); diff --git a/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs b/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs index 6babd1b3..cc4e430d 100644 --- a/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs +++ b/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs @@ -128,8 +128,17 @@ namespace FreeSql.Tests.Oracle { var dt2 = select.Limit(10).ToDataTable("id, 111222"); var dt3 = select.Limit(10).ToDataTable(a => new { a.Id, a.Type.Name, now = DateTime.Now }); } + class TestDto { + public int id { get; set; } + public string name { get; set; } + } [Fact] public void ToList() { + + var testDto1 = select.Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title }); + var testDto2 = select.Limit(10).ToList(a => new TestDto()); + var testDto3 = select.Limit(10).ToList(a => new TestDto { }); + var testDto4 = select.Limit(10).ToList(a => new TestDto() { }); } [Fact] public void ToOne() { diff --git a/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs b/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs index b0bd6fff..c94f0f9c 100644 --- a/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs +++ b/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs @@ -119,8 +119,19 @@ namespace FreeSql.Tests.PostgreSQL { var dt2 = select.Limit(10).ToDataTable("id, 222"); var dt3 = select.Limit(10).ToDataTable(a => new { a.Id, a.Type.Name, now = DateTime.Now }); } + class TestDto { + public int id { get; set; } + public string name { get; set; } + } [Fact] public void ToList() { + + var testDto1 = select.Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title }); + var testDto2 = select.Limit(10).ToList(a => new TestDto()); + var testDto3 = select.Limit(10).ToList(a => new TestDto { }); + var testDto4 = select.Limit(10).ToList(a => new TestDto() { }); + + var t1 = g.pgsql.Select().Where("").Where(a => a.Id > 0).Skip(100).Limit(200).ToSql(); var t2 = g.pgsql.Select().As("b").Where("").Where(a => a.Id > 0).Skip(100).Limit(200).ToSql(); diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs index 03fe8af7..7cb330aa 100644 --- a/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs @@ -130,8 +130,17 @@ namespace FreeSql.Tests.SqlServer { var dt2 = select.Limit(10).ToDataTable("id, getdate()"); var dt3 = select.Limit(10).ToDataTable(a => new { a.Id, a.Type.Name, now = DateTime.Now }); } + class TestDto { + public int id { get; set; } + public string name { get; set; } + } [Fact] public void ToList() { + + var testDto1 = select.Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title }); + var testDto2 = select.Limit(10).ToList(a => new TestDto()); + var testDto3 = select.Limit(10).ToList(a => new TestDto { }); + var testDto4 = select.Limit(10).ToList(a => new TestDto() { }); } [Fact] public void ToOne() { diff --git a/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs b/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs index 991e0694..c6ce7c0f 100644 --- a/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs +++ b/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs @@ -122,8 +122,17 @@ namespace FreeSql.Tests.Sqlite { var dt2 = select.Limit(10).ToDataTable("id, 111222"); var dt3 = select.Limit(10).ToDataTable(a => new { a.Id, a.Type.Name, now = DateTime.Now }); } + class TestDto { + public int id { get; set; } + public string name { get; set; } + } [Fact] public void ToList() { + + var testDto1 = select.Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title }); + var testDto2 = select.Limit(10).ToList(a => new TestDto()); + var testDto3 = select.Limit(10).ToList(a => new TestDto { }); + var testDto4 = select.Limit(10).ToList(a => new TestDto() { }); } [Fact] public void ToOne() { diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index d359442c..91b6fc3c 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -17,6 +17,7 @@ namespace FreeSql.Internal { _common = common; } + static ConcurrentDictionary _dicReadAnonymousFieldDtoPropertys = new ConcurrentDictionary(); internal bool ReadAnonymousField(List _tables, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp, Func getSelectGroupingMapString) { switch (exp.NodeType) { case ExpressionType.Quote: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand, getSelectGroupingMapString); @@ -78,17 +79,72 @@ namespace FreeSql.Internal { return false; } return false; + case ExpressionType.MemberInit: + var initExp = exp as MemberInitExpression; + parent.Consturctor = initExp.NewExpression.Type.GetConstructors()[0]; + parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties; + if (initExp.Bindings?.Count > 0) { + //指定 dto映射 + for (var a = 0; a < initExp.Bindings.Count; a++) { + var initAssignExp = (initExp.Bindings[a] as MemberAssignment); + if (initAssignExp == null) continue; + var child = new ReadAnonymousTypeInfo { + Property = initExp.Type.GetProperty(initExp.Bindings[a].Member.Name, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance), + CsName = initExp.Bindings[a].Member.Name, + CsType = initAssignExp.Expression.Type + }; + parent.Childs.Add(child); + ReadAnonymousField(_tables, field, child, ref index, initAssignExp.Expression, getSelectGroupingMapString); + } + } else { + //dto 映射 + var dtoProps = _dicReadAnonymousFieldDtoPropertys.GetOrAdd(initExp.NewExpression.Type, dtoType => dtoType.GetProperties()); + var dtoTb0 = _tables.First(); + foreach (var dtoProp in dtoProps) { + if (dtoTb0.Table.Columns.TryGetValue(dtoProp.Name, out var trydtocol)) { + var child = new ReadAnonymousTypeInfo { + Property = dtoProp, + CsName = dtoProp.Name, + CsType = dtoProp.PropertyType + }; + parent.Childs.Add(child); + ReadAnonymousField(_tables, field, child, ref index, Expression.Property(dtoTb0.Parameter, dtoTb0.Table.Properties[trydtocol.CsName]), getSelectGroupingMapString); + } + } + if (parent.Childs.Any() == false) throw new Exception($"映射异常:{initExp.NewExpression.Type.Name} 没有一个属性名和 {dtoTb0.Table.Type.Name} 相同"); + } + return true; case ExpressionType.New: var newExp = exp as NewExpression; parent.Consturctor = newExp.Type.GetConstructors()[0]; parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Arguments; - for (var a = 0; a < newExp.Members.Count; a++) { - var child = new ReadAnonymousTypeInfo { - Property = newExp.Type.GetProperty(newExp.Members[a].Name, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance), - CsName = newExp.Members[a].Name, CsType = newExp.Arguments[a].Type - }; - parent.Childs.Add(child); - ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a], getSelectGroupingMapString); + if (newExp.Members?.Count > 0) { + for (var a = 0; a < newExp.Members.Count; a++) { + var child = new ReadAnonymousTypeInfo { + Property = newExp.Type.GetProperty(newExp.Members[a].Name, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance), + CsName = newExp.Members[a].Name, + CsType = newExp.Arguments[a].Type + }; + parent.Childs.Add(child); + ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a], getSelectGroupingMapString); + } + } else { + //dto 映射 + parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties; + var dtoProps = _dicReadAnonymousFieldDtoPropertys.GetOrAdd(newExp.Type, dtoType => dtoType.GetProperties()); + var dtoTb0 = _tables.First(); + foreach (var dtoProp in dtoProps) { + if (dtoTb0.Table.Columns.TryGetValue(dtoProp.Name, out var trydtocol)) { + var child = new ReadAnonymousTypeInfo { + Property = dtoProp, + CsName = dtoProp.Name, + CsType = dtoProp.PropertyType + }; + parent.Childs.Add(child); + ReadAnonymousField(_tables, field, child, ref index, Expression.Property(dtoTb0.Parameter, dtoTb0.Table.Properties[trydtocol.CsName]), getSelectGroupingMapString); + } + } + if (parent.Childs.Any() == false) throw new Exception($"映射异常:{newExp.Type.Name} 没有一个属性名和 {dtoTb0.Table.Type.Name} 相同"); } return true; } @@ -121,7 +177,7 @@ namespace FreeSql.Internal { var prop = parent.Childs[b].Property; var objval = ReadAnonymous(parent.Childs[b], dr, ref index, notRead); var safeval = Utils.GetDataReaderValue(prop.PropertyType, objval); - if (isnull == false && safeval == null && parent.Table.ColumnsByCs.TryGetValue(parent.Childs[b].CsName, out var trycol) && trycol.Attribute.IsPrimary) + if (isnull == false && safeval == null && parent.Table != null && parent.Table.ColumnsByCs.TryGetValue(parent.Childs[b].CsName, out var trycol) && trycol.Attribute.IsPrimary) isnull = true; if (isnull == false) prop.SetValue(ret, safeval, null);