diff --git a/FreeSql.Tests/FreeSql.Tests/Issues/623.cs b/FreeSql.Tests/FreeSql.Tests/Issues/623.cs index db0da73b..5898fc43 100644 --- a/FreeSql.Tests/FreeSql.Tests/Issues/623.cs +++ b/FreeSql.Tests/FreeSql.Tests/Issues/623.cs @@ -44,7 +44,7 @@ namespace FreeSql.Tests.Issues FacilityCount = a.Sum(a.Value.FacilityCount), FacilityOpenCount = a.Sum(a.Value.FacilityOpenCount) }); - Assert.Equal(@"SELECT a.`Dot`, sum(a.`FacilityCount`) as1, sum(a.`FacilityOpenCount`) as2 + Assert.Equal(@"SELECT a.`Dot` as1, sum(a.`FacilityCount`) as2, sum(a.`FacilityOpenCount`) as3 FROM `ts_facility` a WHERE (a.`Date` = cast(date_format('2020-12-30 00:00:00.000','%Y-%m-%d') as datetime)) AND (((a.`EnterpriseId`) in (5))) AND (a.`FacilityType` = 1) GROUP BY a.`Dot`", sql); diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index e0ffb9c1..9124dd68 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -48,7 +48,7 @@ public static partial class FreeSqlGlobalExtensions }); public static bool IsIntegerType(this Type that) => that == null ? false : (_dicIsNumberType.Value.TryGetValue(that, out var tryval) ? tryval : false); public static bool IsNumberType(this Type that) => that == null ? false : _dicIsNumberType.Value.ContainsKey(that); - public static bool IsNullableType(this Type that) => that.IsArray == false && that?.FullName.StartsWith("System.Nullable`1[") == true; + public static bool IsNullableType(this Type that) => that == null ? false : (that.IsArray == false && that.FullName.StartsWith("System.Nullable`1[") == true); public static bool IsAnonymousType(this Type that) => that == null ? false : (that.FullName.StartsWith("<>f__AnonymousType") || that.FullName.StartsWith("VB$AnonymousType")); public static bool IsArrayOrList(this Type that) => that == null ? false : (that.IsArray || typeof(IList).IsAssignableFrom(that)); public static Type NullableTypeOrThis(this Type that) => that?.IsNullableType() == true ? that.GetGenericArguments().First() : that; diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 2db205b7..434ec7a2 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -4440,6 +4440,23 @@ 中间表,多对多 + + + PostgreSQL 数组类型专属功能 + 方式一:select * from Role where Id in (RoleIds) + class User { + ____public int[] RoleIds { get; set; } + ____[Navigate(nameof(RoleIds))] + ____public List<Role> Roles { get; set; } + } + 方式二:select * from User where RoleIds @> Id + class Role { + ____public int Id { get; set; } + ____[Navigate(nameof(User.RoleIds))] + ____public List<User> Users { get; set; } + } + + 是否可用 diff --git a/FreeSql/Internal/Model/TableInfo.cs b/FreeSql/Internal/Model/TableInfo.cs index 1349e952..6c858314 100644 --- a/FreeSql/Internal/Model/TableInfo.cs +++ b/FreeSql/Internal/Model/TableInfo.cs @@ -150,6 +150,22 @@ namespace FreeSql.Internal.Model } public enum TableRefType { - OneToOne, ManyToOne, OneToMany, ManyToMany, PgArrayToMany + OneToOne, ManyToOne, OneToMany, ManyToMany, + /// + /// PostgreSQL 数组类型专属功能 + /// 方式一:select * from Role where Id in (RoleIds) + /// class User { + /// ____public int[] RoleIds { get; set; } + /// ____[Navigate(nameof(RoleIds))] + /// ____public List<Role> Roles { get; set; } + /// } + /// 方式二:select * from User where RoleIds @> Id + /// class Role { + /// ____public int Id { get; set; } + /// ____[Navigate(nameof(User.RoleIds))] + /// ____public List<User> Users { get; set; } + /// } + /// + PgArrayToMany } } \ No newline at end of file diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 73163bcc..7e852d3b 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -1014,7 +1014,8 @@ namespace FreeSql.Internal { if (trytb.ColumnsByCs.TryGetValue(pnvBind[0], out trycol)) { - if (trycol.CsType.IsArray == true && tbref.Primarys[0].CsType.NullableTypeOrThis() != trycol.CsType.GetElementType().NullableTypeOrThis()) + if (trycol.CsType.IsArray == false) trycol = null; + else if (trycol != null && tbref.Primarys[0].CsType.NullableTypeOrThis() != trycol.CsType.GetElementType().NullableTypeOrThis()) { nvref.Exception = new Exception($"导航属性 {trytbTypeName}.{pnv.Name} 特性 [Navigate] 解析错误,{trytbTypeName}.{trycol.CsName} 数组元素 与 {tbrefTypeName}.{tbref.Primarys[0].CsName} 类型不符"); trytb.AddOrUpdateTableRef(pnv.Name, nvref); @@ -1022,7 +1023,7 @@ namespace FreeSql.Internal } } } - if (nvref.Exception == null && trycol == null) + if (pnvBind == null && trycol == null) { var findtbrefPkCsName = tbref.Primarys[0].CsName.TrimStart('_'); if (findtbrefPkCsName.StartsWith(trytb.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtbrefPkCsName = findtbrefPkCsName.Substring(trytb.Type.Name.Length).TrimStart('_'); @@ -1059,7 +1060,8 @@ namespace FreeSql.Internal { if (tbref.ColumnsByCs.TryGetValue(pnvBind[0], out trycol)) { - if (trycol.CsType.IsArray == true && trytb.Primarys[0].CsType.NullableTypeOrThis() != trycol.CsType.GetElementType().NullableTypeOrThis()) + if (trycol.CsType.IsArray == false) trycol = null; + else if (trytb.Primarys[0].CsType.NullableTypeOrThis() != trycol.CsType.GetElementType().NullableTypeOrThis()) { nvref.Exception = new Exception($"导航属性 {trytbTypeName}.{pnv.Name} 特性 [Navigate] 解析错误,{trytbTypeName}.{trytb.Primarys[0].CsName} 与 {tbrefTypeName}.{trycol.CsName} 数组元素类型不符"); trytb.AddOrUpdateTableRef(pnv.Name, nvref); @@ -1067,7 +1069,7 @@ namespace FreeSql.Internal } } } - if (nvref.Exception == null && trycol == null) + if (pnvBind != null && trycol == null) { var findtrytbPkCsName = trytb.Primarys[0].CsName.TrimStart('_'); if (findtrytbPkCsName.StartsWith(trytb.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtrytbPkCsName = findtrytbPkCsName.Substring(trytb.Type.Name.Length).TrimStart('_'); @@ -1086,9 +1088,12 @@ namespace FreeSql.Internal isArrayToMany = trycol != null; if (isArrayToMany) { - cscodeExtLogic = $" if (this.{trytb.Primarys[0].CsName} == null) return null;\r\n"; lmbdWhere.Append("a.").Append(trycol.CsName).Append(".Contains(this.").Append(trytb.Primarys[0].CsName); - if (trycol.CsType.GetElementType().IsNullableType() == false && trytb.Primarys[0].CsType.IsNullableType()) lmbdWhere.Append(".Value"); + if (trycol.CsType.GetElementType().IsNullableType() == false && trytb.Primarys[0].CsType.IsNullableType()) + { + lmbdWhere.Append(".Value"); + cscodeExtLogic = $" if (this.{trytb.Primarys[0].CsName} == null) return null;\r\n"; + } lmbdWhere.Append(")"); nvref.Columns.Add(tbref.Primarys[0]); nvref.RefColumns.Add(trycol);