mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	SQL命令执行监视 + Pgsql表达式(Array/HStore/Jsonb)实现与测试
This commit is contained in:
		@@ -58,6 +58,9 @@ namespace FreeSql.Tests.PostgreSQL {
 | 
				
			|||||||
		public void CurdAllField() {
 | 
							public void CurdAllField() {
 | 
				
			||||||
			NpgsqlConnection.GlobalTypeMapper.UseLegacyPostgis();
 | 
								NpgsqlConnection.GlobalTypeMapper.UseLegacyPostgis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql1 = select.Where(a => a.testFieldIntArray.Contains(1)).ToSql();
 | 
				
			||||||
 | 
								var sql2 = select.Where(a => a.testFieldIntArray.Contains(1)).ToSql();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var item = new TableAllType { };
 | 
								var item = new TableAllType { };
 | 
				
			||||||
			item.Id = (int)insert.AppendData(item).ExecuteIdentity();
 | 
								item.Id = (int)insert.AppendData(item).ExecuteIdentity();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										249
									
								
								FreeSql.Tests/PostgreSQL/PostgreSQLExpression/OtherTest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								FreeSql.Tests/PostgreSQL/PostgreSQLExpression/OtherTest.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using Npgsql;
 | 
				
			||||||
 | 
					using Npgsql.LegacyPostgis;
 | 
				
			||||||
 | 
					using NpgsqlTypes;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.NetworkInformation;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.PostgreSQLExpression {
 | 
				
			||||||
 | 
						public class OtherTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ISelect<TableAllType> select => g.pgsql.Select<TableAllType>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public OtherTest() {
 | 
				
			||||||
 | 
								NpgsqlConnection.GlobalTypeMapper.UseLegacyPostgis();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[Fact]
 | 
				
			||||||
 | 
							public void Array() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql1 = select.Where(a => a.testFieldIntArray.Contains(1)).ToList();
 | 
				
			||||||
 | 
								var sql2 = select.Where(a => a.testFieldIntArray.Contains(1) == false).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql3 = select.Where(a => a.testFieldIntArray.Any()).ToList();
 | 
				
			||||||
 | 
								var sql4 = select.Where(a => a.testFieldIntArray.Any() == false).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql5 = select.ToList(a => a.testFieldIntArray.Concat(new[] { 1, 2, 3 }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql6 = select.Where(a => a.testFieldIntArray.GetLength(1) > 0).ToList();
 | 
				
			||||||
 | 
								var sql7 = select.Where(a => a.testFieldIntArray.GetLongLength(1) > 0).ToList();
 | 
				
			||||||
 | 
								var sql8 = select.Where(a => a.testFieldIntArray.Length > 0).ToList();
 | 
				
			||||||
 | 
								var sql9 = select.Where(a => a.testFieldIntArray.Count() > 0).ToList();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[Fact]
 | 
				
			||||||
 | 
							public void Jsonb() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql1 = select.Where(a => a.testFieldJToken.Contains(JToken.Parse("{a:1}"))).ToList();
 | 
				
			||||||
 | 
								var sql2 = select.Where(a => a.testFieldJToken.Contains(JToken.Parse("{a:1}")) == false).ToList();
 | 
				
			||||||
 | 
								var sql111 = select.Where(a => a.testFieldJToken.Contains("{a:1}")).ToList();
 | 
				
			||||||
 | 
								var sql222 = select.Where(a => a.testFieldJToken.Contains("{a:1}") == false).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql3 = select.Where(a => a.testFieldJObject.ContainsKey("a")).ToList();
 | 
				
			||||||
 | 
								var sql4 = select.Where(a => a.testFieldJObject.ContainsKey("a") == false).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql5 = select.Where(a => a.testFieldJArray.Contains(JToken.Parse("{a:1}"))).ToList();
 | 
				
			||||||
 | 
								var sql6 = select.Where(a => a.testFieldJArray.Contains(JToken.Parse("{a:1}")) == false).ToList();
 | 
				
			||||||
 | 
								var sql555 = select.Where(a => a.testFieldJArray.Contains("{a:1}")).ToList();
 | 
				
			||||||
 | 
								var sql666 = select.Where(a => a.testFieldJArray.Contains("{a:1}") == false).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//var sql7 = select.Where(a => a.testFieldJToken.Any()).ToList();
 | 
				
			||||||
 | 
								//var sql8 = select.Where(a => a.testFieldJToken.Any() == false).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql9 = select.Where(a => a.testFieldJArray.Any()).ToList();
 | 
				
			||||||
 | 
								var sql10 = select.Where(a => a.testFieldJArray.Any() == false).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//var sql11 = select.ToList(a => a.testFieldJToken.Concat(JToken.Parse("{a:1}")));
 | 
				
			||||||
 | 
								//var sql12 = select.ToList(a => a.testFieldJObject.Concat(JToken.Parse("{a:1}")));
 | 
				
			||||||
 | 
								//var sql13 = select.ToList(a => a.testFieldJArray.Concat(JToken.Parse("{a:1}")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//var sql14 = select.Where(a => a.testFieldJToken.Count() > 0).ToList();
 | 
				
			||||||
 | 
								//var sql15 = select.Where(a => a.testFieldJObject.Count > 0).ToList();
 | 
				
			||||||
 | 
								var sql16 = select.Where(a => a.testFieldJArray.Count() > 0).ToList();
 | 
				
			||||||
 | 
								var sql17 = select.Where(a => a.testFieldJArray.LongCount() > 0).ToList();
 | 
				
			||||||
 | 
								var sql18 = select.Where(a => a.testFieldJArray.Count > 0).ToList();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[Fact]
 | 
				
			||||||
 | 
							public void HStore() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sql1 = select.Where(a => a.testFieldHStore.ContainsKey("a")).ToList();
 | 
				
			||||||
 | 
								var sql2 = select.Where(a => a.testFieldHStore.ContainsKey("a") == false).ToList();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[Table(Name = "tb_alltype")]
 | 
				
			||||||
 | 
							class TableAllType {
 | 
				
			||||||
 | 
								[Column(IsIdentity = true, IsPrimary = true)]
 | 
				
			||||||
 | 
								public int Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public bool testFieldBool { get; set; }
 | 
				
			||||||
 | 
								public sbyte testFieldSByte { get; set; }
 | 
				
			||||||
 | 
								public short testFieldShort { get; set; }
 | 
				
			||||||
 | 
								public int testFieldInt { get; set; }
 | 
				
			||||||
 | 
								public long testFieldLong { get; set; }
 | 
				
			||||||
 | 
								public byte testFieldByte { get; set; }
 | 
				
			||||||
 | 
								public ushort testFieldUShort { get; set; }
 | 
				
			||||||
 | 
								public uint testFieldUInt { get; set; }
 | 
				
			||||||
 | 
								public ulong testFieldULong { get; set; }
 | 
				
			||||||
 | 
								public double testFieldDouble { get; set; }
 | 
				
			||||||
 | 
								public float testFieldFloat { get; set; }
 | 
				
			||||||
 | 
								public decimal testFieldDecimal { get; set; }
 | 
				
			||||||
 | 
								public TimeSpan testFieldTimeSpan { get; set; }
 | 
				
			||||||
 | 
								public DateTime testFieldDateTime { get; set; }
 | 
				
			||||||
 | 
								public byte[] testFieldBytes { get; set; }
 | 
				
			||||||
 | 
								public string testFieldString { get; set; }
 | 
				
			||||||
 | 
								public Guid testFieldGuid { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPoint testFieldNpgsqlPoint { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLine testFieldNpgsqlLine { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLSeg testFieldNpgsqlLSeg { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlBox testFieldNpgsqlBox { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPath testFieldNpgsqlPath { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPolygon testFieldNpgsqlPolygon { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlCircle testFieldNpgsqlCircle { get; set; }
 | 
				
			||||||
 | 
								public (IPAddress Address, int Subnet) testFieldCidr { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<int> testFieldInt4range { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<long> testFieldInt8range { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<decimal> testFieldNumrange { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<DateTime> testFieldTsrange { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public bool? testFieldBoolNullable { get; set; }
 | 
				
			||||||
 | 
								public sbyte? testFieldSByteNullable { get; set; }
 | 
				
			||||||
 | 
								public short? testFieldShortNullable { get; set; }
 | 
				
			||||||
 | 
								public int? testFieldIntNullable { get; set; }
 | 
				
			||||||
 | 
								public long? testFielLongNullable { get; set; }
 | 
				
			||||||
 | 
								public byte? testFieldByteNullable { get; set; }
 | 
				
			||||||
 | 
								public ushort? testFieldUShortNullable { get; set; }
 | 
				
			||||||
 | 
								public uint? testFieldUIntNullable { get; set; }
 | 
				
			||||||
 | 
								public ulong? testFieldULongNullable { get; set; }
 | 
				
			||||||
 | 
								public double? testFieldDoubleNullable { get; set; }
 | 
				
			||||||
 | 
								public float? testFieldFloatNullable { get; set; }
 | 
				
			||||||
 | 
								public decimal? testFieldDecimalNullable { get; set; }
 | 
				
			||||||
 | 
								public TimeSpan? testFieldTimeSpanNullable { get; set; }
 | 
				
			||||||
 | 
								public DateTime? testFieldDateTimeNullable { get; set; }
 | 
				
			||||||
 | 
								public Guid? testFieldGuidNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPoint? testFieldNpgsqlPointNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLine? testFieldNpgsqlLineNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLSeg? testFieldNpgsqlLSegNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlBox? testFieldNpgsqlBoxNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPath? testFieldNpgsqlPathNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPolygon? testFieldNpgsqlPolygonNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlCircle? testFieldNpgsqlCircleNullable { get; set; }
 | 
				
			||||||
 | 
								public (IPAddress Address, int Subnet)? testFieldCidrNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<int>? testFieldInt4rangeNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<long>? testFieldInt8rangeNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<decimal>? testFieldNumrangeNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<DateTime>? testFieldTsrangeNullable { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public BitArray testFieldBitArray { get; set; }
 | 
				
			||||||
 | 
								public IPAddress testFieldInet { get; set; }
 | 
				
			||||||
 | 
								public PhysicalAddress testFieldMacaddr { get; set; }
 | 
				
			||||||
 | 
								public JToken testFieldJToken { get; set; }
 | 
				
			||||||
 | 
								public JObject testFieldJObject { get; set; }
 | 
				
			||||||
 | 
								public JArray testFieldJArray { get; set; }
 | 
				
			||||||
 | 
								public Dictionary<string, string> testFieldHStore { get; set; }
 | 
				
			||||||
 | 
								public PostgisPoint testFieldPostgisPoint { get; set; }
 | 
				
			||||||
 | 
								public PostgisLineString testFieldPostgisLineString { get; set; }
 | 
				
			||||||
 | 
								public PostgisPolygon testFieldPostgisPolygon { get; set; }
 | 
				
			||||||
 | 
								public PostgisMultiPoint testFieldPostgisMultiPoint { get; set; }
 | 
				
			||||||
 | 
								public PostgisMultiLineString testFieldPostgisPostgisMultiLineString { get; set; }
 | 
				
			||||||
 | 
								public PostgisMultiPolygon testFieldPostgisPostgisMultiPolygon { get; set; }
 | 
				
			||||||
 | 
								public PostgisGeometry testFieldPostgisGeometry { get; set; }
 | 
				
			||||||
 | 
								public PostgisGeometryCollection testFieldPostgisGeometryCollection { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public TableAllTypeEnumType1 testFieldEnum1 { get; set; }
 | 
				
			||||||
 | 
								public TableAllTypeEnumType1? testFieldEnum1Nullable { get; set; }
 | 
				
			||||||
 | 
								public TableAllTypeEnumType2 testFieldEnum2 { get; set; }
 | 
				
			||||||
 | 
								public TableAllTypeEnumType2? testFieldEnum2Nullable { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* array */
 | 
				
			||||||
 | 
								public bool[] testFieldBoolArray { get; set; }
 | 
				
			||||||
 | 
								public sbyte[] testFieldSByteArray { get; set; }
 | 
				
			||||||
 | 
								public short[] testFieldShortArray { get; set; }
 | 
				
			||||||
 | 
								public int[] testFieldIntArray { get; set; }
 | 
				
			||||||
 | 
								public long[] testFieldLongArray { get; set; }
 | 
				
			||||||
 | 
								public byte[] testFieldByteArray { get; set; }
 | 
				
			||||||
 | 
								public ushort[] testFieldUShortArray { get; set; }
 | 
				
			||||||
 | 
								public uint[] testFieldUIntArray { get; set; }
 | 
				
			||||||
 | 
								public ulong[] testFieldULongArray { get; set; }
 | 
				
			||||||
 | 
								public double[] testFieldDoubleArray { get; set; }
 | 
				
			||||||
 | 
								public float[] testFieldFloatArray { get; set; }
 | 
				
			||||||
 | 
								public decimal[] testFieldDecimalArray { get; set; }
 | 
				
			||||||
 | 
								public TimeSpan[] testFieldTimeSpanArray { get; set; }
 | 
				
			||||||
 | 
								public DateTime[] testFieldDateTimeArray { get; set; }
 | 
				
			||||||
 | 
								public byte[][] testFieldBytesArray { get; set; }
 | 
				
			||||||
 | 
								public string[] testFieldStringArray { get; set; }
 | 
				
			||||||
 | 
								public Guid[] testFieldGuidArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPoint[] testFieldNpgsqlPointArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLine[] testFieldNpgsqlLineArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLSeg[] testFieldNpgsqlLSegArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlBox[] testFieldNpgsqlBoxArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPath[] testFieldNpgsqlPathArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPolygon[] testFieldNpgsqlPolygonArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlCircle[] testFieldNpgsqlCircleArray { get; set; }
 | 
				
			||||||
 | 
								public (IPAddress Address, int Subnet)[] testFieldCidrArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<int>[] testFieldInt4rangeArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<long>[] testFieldInt8rangeArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<decimal>[] testFieldNumrangeArray { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<DateTime>[] testFieldTsrangeArray { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public bool?[] testFieldBoolArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public sbyte?[] testFieldSByteArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public short?[] testFieldShortArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public int?[] testFieldIntArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public long?[] testFielLongArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public byte?[] testFieldByteArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public ushort?[] testFieldUShortArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public uint?[] testFieldUIntArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public ulong?[] testFieldULongArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public double?[] testFieldDoubleArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public float?[] testFieldFloatArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public decimal?[] testFieldDecimalArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public TimeSpan?[] testFieldTimeSpanArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public DateTime?[] testFieldDateTimeArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public Guid?[] testFieldGuidArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPoint?[] testFieldNpgsqlPointArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLine?[] testFieldNpgsqlLineArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlLSeg?[] testFieldNpgsqlLSegArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlBox?[] testFieldNpgsqlBoxArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPath?[] testFieldNpgsqlPathArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlPolygon?[] testFieldNpgsqlPolygonArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlCircle?[] testFieldNpgsqlCircleArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public (IPAddress Address, int Subnet)?[] testFieldCidrArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<int>?[] testFieldInt4rangeArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<long>?[] testFieldInt8rangeArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<decimal>?[] testFieldNumrangeArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public NpgsqlRange<DateTime>?[] testFieldTsrangeArrayNullable { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public BitArray[] testFieldBitArrayArray { get; set; }
 | 
				
			||||||
 | 
								public IPAddress[] testFieldInetArray { get; set; }
 | 
				
			||||||
 | 
								public PhysicalAddress[] testFieldMacaddrArray { get; set; }
 | 
				
			||||||
 | 
								public JToken[] testFieldJTokenArray { get; set; }
 | 
				
			||||||
 | 
								public JObject[] testFieldJObjectArray { get; set; }
 | 
				
			||||||
 | 
								public JArray[] testFieldJArrayArray { get; set; }
 | 
				
			||||||
 | 
								public Dictionary<string, string>[] testFieldHStoreArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisPoint[] testFieldPostgisPointArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisLineString[] testFieldPostgisLineStringArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisPolygon[] testFieldPostgisPolygonArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisMultiPoint[] testFieldPostgisMultiPointArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisMultiLineString[] testFieldPostgisPostgisMultiLineStringArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisMultiPolygon[] testFieldPostgisPostgisMultiPolygonArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisGeometry[] testFieldPostgisGeometryArray { get; set; }
 | 
				
			||||||
 | 
								public PostgisGeometryCollection[] testFieldPostgisGeometryCollectionArray { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public TableAllTypeEnumType1[] testFieldEnum1Array { get; set; }
 | 
				
			||||||
 | 
								public TableAllTypeEnumType1?[] testFieldEnum1ArrayNullable { get; set; }
 | 
				
			||||||
 | 
								public TableAllTypeEnumType2[] testFieldEnum2Array { get; set; }
 | 
				
			||||||
 | 
								public TableAllTypeEnumType2?[] testFieldEnum2ArrayNullable { get; set; }
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public enum TableAllTypeEnumType1 { e1, e2, e3, e5 }
 | 
				
			||||||
 | 
							[Flags] public enum TableAllTypeEnumType2 { f1, f2, f3 }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,9 @@ using System;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using NpgsqlTypes;
 | 
				
			||||||
 | 
					using Npgsql.LegacyPostgis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.Tests {
 | 
					namespace FreeSql.Tests {
 | 
				
			||||||
	public class UnitTest1 {
 | 
						public class UnitTest1 {
 | 
				
			||||||
@@ -25,15 +28,11 @@ namespace FreeSql.Tests {
 | 
				
			|||||||
			.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
 | 
								.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
 | 
				
			||||||
			.OrderBy(a => a.Key.tt2)
 | 
								.OrderBy(a => a.Key.tt2)
 | 
				
			||||||
			.OrderByDescending(a => a.Count())
 | 
								.OrderByDescending(a => a.Count())
 | 
				
			||||||
			.ToSql(a => new { a.Key.tt2, cou1 = a.Count(), arg1 = a.Avg(a.Key.mod4),
 | 
								.ToList(a => new { a.Key.tt2, cou1 = a.Count(), arg1 = a.Avg(a.Key.mod4),
 | 
				
			||||||
				ccc2 = a.Key.tt2 ?? "now()",
 | 
									ccc2 = a.Key.tt2 ?? "now()",
 | 
				
			||||||
				ccc = Convert.ToDateTime("now()"), partby = Convert.ToDecimal("sum(num) over(PARTITION BY server_id,os,rid,chn order by id desc)")
 | 
									//ccc = Convert.ToDateTime("now()"), partby = Convert.ToDecimal("sum(num) over(PARTITION BY server_id,os,rid,chn order by id desc)")
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
 | 
					 | 
				
			||||||
			var sss = new[] { 1, 2, 3 };
 | 
					 | 
				
			||||||
			sss.Count();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			var arrg = g.mysql.Select<TestInfo>().ToAggregate(a => new { sum = a.Sum(a.Key.Id + 11.11), avg = a.Avg(a.Key.Id), count = a.Count(), max = a.Max(a.Key.Id), min = a.Min(a.Key.Id) });
 | 
								var arrg = g.mysql.Select<TestInfo>().ToAggregate(a => new { sum = a.Sum(a.Key.Id + 11.11), avg = a.Avg(a.Key.Id), count = a.Count(), max = a.Max(a.Key.Id), min = a.Min(a.Key.Id) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var arrg222 = g.mysql.Select<NullAggreTestTable>().ToAggregate(a => new { sum = a.Sum(a.Key.Id + 11.11), avg = a.Avg(a.Key.Id), count = a.Count(), max = a.Max(a.Key.Id), min = a.Min(a.Key.Id) });
 | 
								var arrg222 = g.mysql.Select<NullAggreTestTable>().ToAggregate(a => new { sum = a.Sum(a.Key.Id + 11.11), avg = a.Avg(a.Key.Id), count = a.Count(), max = a.Max(a.Key.Id), min = a.Min(a.Key.Id) });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,14 @@ public class g {
 | 
				
			|||||||
	public static IFreeSql mysql = new FreeSql.FreeSqlBuilder()
 | 
						public static IFreeSql mysql = new FreeSql.FreeSqlBuilder()
 | 
				
			||||||
		.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
 | 
							.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
 | 
				
			||||||
		.UseAutoSyncStructure(true)
 | 
							.UseAutoSyncStructure(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							.UseMonitorCommand(
 | 
				
			||||||
 | 
								cmd => {
 | 
				
			||||||
 | 
									Console.WriteLine(cmd.CommandText);
 | 
				
			||||||
 | 
								}, //监听SQL命令对象,在执行前
 | 
				
			||||||
 | 
								(cmd, traceLog) => {
 | 
				
			||||||
 | 
									Console.WriteLine(traceLog);
 | 
				
			||||||
 | 
								}) //监听SQL命令对象,在执行后
 | 
				
			||||||
		.Build();
 | 
							.Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder()
 | 
						public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql {
 | 
					namespace FreeSql {
 | 
				
			||||||
@@ -13,6 +14,8 @@ namespace FreeSql {
 | 
				
			|||||||
		string[] _slaveConnectionString;
 | 
							string[] _slaveConnectionString;
 | 
				
			||||||
		bool _isAutoSyncStructure = false;
 | 
							bool _isAutoSyncStructure = false;
 | 
				
			||||||
		bool _isSyncStructureToLower = false;
 | 
							bool _isSyncStructureToLower = false;
 | 
				
			||||||
 | 
							Action<DbCommand> _aopCommandExecuting = null;
 | 
				
			||||||
 | 
							Action<DbCommand, string> _aopCommandExecuted = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/// <summary>
 | 
							/// <summary>
 | 
				
			||||||
		/// 使用缓存,不指定默认使用内存
 | 
							/// 使用缓存,不指定默认使用内存
 | 
				
			||||||
@@ -71,17 +74,31 @@ namespace FreeSql {
 | 
				
			|||||||
			_isSyncStructureToLower = value;
 | 
								_isSyncStructureToLower = value;
 | 
				
			||||||
			return this;
 | 
								return this;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							/// <summary>
 | 
				
			||||||
 | 
							/// 监视数据库命令对象
 | 
				
			||||||
 | 
							/// </summary>
 | 
				
			||||||
 | 
							/// <param name="executing">执行前</param>
 | 
				
			||||||
 | 
							/// <param name="executed">执行后</param>
 | 
				
			||||||
 | 
							/// <returns></returns>
 | 
				
			||||||
 | 
							public FreeSqlBuilder UseMonitorCommand(Action<DbCommand> executing, Action<DbCommand, string> executed = null) {
 | 
				
			||||||
 | 
								_aopCommandExecuting = executing;
 | 
				
			||||||
 | 
								_aopCommandExecuted = executed;
 | 
				
			||||||
 | 
								return this;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public IFreeSql Build() {
 | 
							public IFreeSql Build() {
 | 
				
			||||||
			IFreeSql ret = null;
 | 
								IFreeSql ret = null;
 | 
				
			||||||
			switch(_dataType) {
 | 
								switch(_dataType) {
 | 
				
			||||||
				case DataType.MySql: ret = new MySql.MySqlProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger); break;
 | 
									case DataType.MySql: ret = new MySql.MySqlProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break;
 | 
				
			||||||
				case DataType.SqlServer: ret = new SqlServer.SqlServerProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger); break;
 | 
									case DataType.SqlServer: ret = new SqlServer.SqlServerProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break;
 | 
				
			||||||
				case DataType.PostgreSQL: ret = new PostgreSQL.PostgreSQLProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger); break;
 | 
									case DataType.PostgreSQL: ret = new PostgreSQL.PostgreSQLProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (ret != null) {
 | 
								if (ret != null) {
 | 
				
			||||||
				ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure;
 | 
									ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure;
 | 
				
			||||||
				ret.CodeFirst.IsSyncStructureToLower = _isSyncStructureToLower;
 | 
									ret.CodeFirst.IsSyncStructureToLower = _isSyncStructureToLower;
 | 
				
			||||||
 | 
									var ado = ret.Ado as Internal.CommonProvider.AdoProvider;
 | 
				
			||||||
 | 
									ado.AopCommandExecuting += _aopCommandExecuting;
 | 
				
			||||||
 | 
									ado.AopCommandExecuted += _aopCommandExecuted;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -222,6 +222,8 @@ namespace FreeSql.Internal {
 | 
				
			|||||||
							case "Min": return $"min({ExpressionLambdaToSql(exp3.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})";
 | 
												case "Min": return $"min({ExpressionLambdaToSql(exp3.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})";
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										var other3Exp = ExpressionLambdaToSqlOther(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
										if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp;
 | 
				
			||||||
					throw new Exception($"未现实函数表达式 {exp3} 解析");
 | 
										throw new Exception($"未现实函数表达式 {exp3} 解析");
 | 
				
			||||||
				case ExpressionType.MemberAccess:
 | 
									case ExpressionType.MemberAccess:
 | 
				
			||||||
					var exp4 = exp as MemberExpression;
 | 
										var exp4 = exp as MemberExpression;
 | 
				
			||||||
@@ -234,6 +236,8 @@ namespace FreeSql.Internal {
 | 
				
			|||||||
						case "System.TimeSpan": extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
											case "System.TimeSpan": extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					if (string.IsNullOrEmpty(extRet) == false) return extRet;
 | 
										if (string.IsNullOrEmpty(extRet) == false) return extRet;
 | 
				
			||||||
 | 
										var other4Exp = ExpressionLambdaToSqlOther(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
										if (string.IsNullOrEmpty(other4Exp) == false) return other4Exp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var expStack = new Stack<Expression>();
 | 
										var expStack = new Stack<Expression>();
 | 
				
			||||||
					expStack.Push(exp);
 | 
										expStack.Push(exp);
 | 
				
			||||||
@@ -341,7 +345,11 @@ namespace FreeSql.Internal {
 | 
				
			|||||||
					return $"{alias2}.{name2}";
 | 
										return $"{alias2}.{name2}";
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			var expBinary = exp as BinaryExpression;
 | 
								var expBinary = exp as BinaryExpression;
 | 
				
			||||||
			if (expBinary == null) return "";
 | 
								if (expBinary == null) {
 | 
				
			||||||
 | 
									var other99Exp = ExpressionLambdaToSqlOther(exp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
									if (string.IsNullOrEmpty(other99Exp) == false) return other99Exp;
 | 
				
			||||||
 | 
									return "";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (expBinary.NodeType == ExpressionType.Coalesce) {
 | 
								if (expBinary.NodeType == ExpressionType.Coalesce) {
 | 
				
			||||||
				return _common.IsNull(
 | 
									return _common.IsNull(
 | 
				
			||||||
					ExpressionLambdaToSql(expBinary.Left, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName),
 | 
										ExpressionLambdaToSql(expBinary.Left, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName),
 | 
				
			||||||
@@ -368,5 +376,6 @@ namespace FreeSql.Internal {
 | 
				
			|||||||
		internal abstract string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
 | 
							internal abstract string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
 | 
				
			||||||
		internal abstract string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
 | 
							internal abstract string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
 | 
				
			||||||
		internal abstract string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
 | 
							internal abstract string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
 | 
				
			||||||
 | 
							internal abstract string ExpressionLambdaToSqlOther(Expression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
		protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex);
 | 
							protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex);
 | 
				
			||||||
		protected abstract DbCommand CreateCommand();
 | 
							protected abstract DbCommand CreateCommand();
 | 
				
			||||||
		protected abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
 | 
							protected abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
 | 
				
			||||||
 | 
							internal Action<DbCommand> AopCommandExecuting = null;
 | 
				
			||||||
 | 
							internal Action<DbCommand, string> AopCommandExecuted = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public bool IsTracePerformance { get; set; } = string.Compare(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), "Development", true) == 0;
 | 
							public bool IsTracePerformance { get; set; } = string.Compare(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), "Development", true) == 0;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@@ -32,10 +34,14 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			if (IsTracePerformance) {
 | 
								if (IsTracePerformance) {
 | 
				
			||||||
				TimeSpan ts = DateTime.Now.Subtract(dt);
 | 
									TimeSpan ts = DateTime.Now.Subtract(dt);
 | 
				
			||||||
				if (e == null && ts.TotalMilliseconds > 100)
 | 
									if (e == null && ts.TotalMilliseconds > 100)
 | 
				
			||||||
					_log.LogWarning($"{pool.Policy.Name}执行SQL语句耗时过长{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n{logtxt}");
 | 
										_log.LogWarning(logtxt = $"{pool.Policy.Name}执行SQL语句耗时过长{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n{logtxt}");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (e == null) {
 | 
				
			||||||
 | 
									AopCommandExecuted?.Invoke(cmd, logtxt);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (e == null) return;
 | 
					 | 
				
			||||||
			string log = $"{pool.Policy.Name}数据库出错(执行SQL)〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓\r\n{cmd.CommandText}\r\n";
 | 
								string log = $"{pool.Policy.Name}数据库出错(执行SQL)〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓\r\n{cmd.CommandText}\r\n";
 | 
				
			||||||
			foreach (DbParameter parm in cmd.Parameters)
 | 
								foreach (DbParameter parm in cmd.Parameters)
 | 
				
			||||||
				log += parm.ParameterName.PadRight(20, ' ') + " = " + ((parm.Value ?? DBNull.Value) == DBNull.Value ? "NULL" : parm.Value) + "\r\n";
 | 
									log += parm.ParameterName.PadRight(20, ' ') + " = " + ((parm.Value ?? DBNull.Value) == DBNull.Value ? "NULL" : parm.Value) + "\r\n";
 | 
				
			||||||
@@ -44,6 +50,9 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_log.LogError(log);
 | 
								_log.LogError(log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			RollbackTransaction();
 | 
								RollbackTransaction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								AopCommandExecuted?.Invoke(cmd, log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			cmd.Parameters.Clear();
 | 
								cmd.Parameters.Clear();
 | 
				
			||||||
			if (isThrowException) throw e;
 | 
								if (isThrowException) throw e;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -261,6 +270,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			AutoCommitTransaction();
 | 
								AutoCommitTransaction();
 | 
				
			||||||
			if (IsTracePerformance) logtxt += $"	AutoCommitTransaction: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
 | 
								if (IsTracePerformance) logtxt += $"	AutoCommitTransaction: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								AopCommandExecuting?.Invoke(cmd);
 | 
				
			||||||
			return (tran, cmd);
 | 
								return (tran, cmd);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -209,6 +209,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (IsTracePerformance) logtxt += $"	PrepareCommand_tran==null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmd.Parameters.Count}\r\n";
 | 
								if (IsTracePerformance) logtxt += $"	PrepareCommand_tran==null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmd.Parameters.Count}\r\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								AopCommandExecuting?.Invoke(cmd);
 | 
				
			||||||
			return cmd;
 | 
								return cmd;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -210,13 +210,13 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		protected (ReadAnonymousTypeInfo map, string field) GetNewExpressionField(NewExpression newexp) {
 | 
							protected (ReadAnonymousTypeInfo map, string field) GetExpressionField(Expression newexp) {
 | 
				
			||||||
			var map = new ReadAnonymousTypeInfo();
 | 
								var map = new ReadAnonymousTypeInfo();
 | 
				
			||||||
			var field = new StringBuilder();
 | 
								var field = new StringBuilder();
 | 
				
			||||||
			var index = 0;
 | 
								var index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp, null);
 | 
								_commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp, null);
 | 
				
			||||||
			return (map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null);
 | 
								return (map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		protected (ReadAnonymousTypeInfo map, string field) GetAllField() {
 | 
							protected (ReadAnonymousTypeInfo map, string field) GetAllField() {
 | 
				
			||||||
			var type = typeof(T1);
 | 
								var type = typeof(T1);
 | 
				
			||||||
@@ -281,7 +281,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			var index = -10000; //临时规则,不返回 as1
 | 
								var index = -10000; //临时规则,不返回 as1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_commonExpression.ReadAnonymousField(_tables, field, map, ref index, columns, null);
 | 
								_commonExpression.ReadAnonymousField(_tables, field, map, ref index, columns, null);
 | 
				
			||||||
			this.GroupBy(map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null);
 | 
								this.GroupBy(field.Length > 0 ? field.Remove(0, 2).ToString() : null);
 | 
				
			||||||
			return new SelectGroupingProvider<TKey>(this, map, _commonExpression);
 | 
								return new SelectGroupingProvider<TKey>(this, map, _commonExpression);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType) {
 | 
							protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType) {
 | 
				
			||||||
@@ -298,9 +298,12 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
		protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null));
 | 
							protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null));
 | 
				
			||||||
		protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC");
 | 
							protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		protected List<TReturn> InternalToList<TReturn>(Expression select) => this.ToListMapReader<TReturn>(this.GetNewExpressionField(select as NewExpression));
 | 
							protected List<TReturn> InternalToList<TReturn>(Expression select) => this.ToListMapReader<TReturn>(this.GetExpressionField(select));
 | 
				
			||||||
		protected Task<List<TReturn>> InternalToListAsync<TReturn>(Expression select) => this.ToListMapReaderAsync<TReturn>(this.GetNewExpressionField(select as NewExpression));
 | 
							protected Task<List<TReturn>> InternalToListAsync<TReturn>(Expression select) => this.ToListMapReaderAsync<TReturn>(this.GetExpressionField(select));
 | 
				
			||||||
		protected string InternalToSql<TReturn>(Expression select) => this.ToSql(this.GetNewExpressionField(select as NewExpression).field);
 | 
							protected string InternalToSql<TReturn>(Expression select) {
 | 
				
			||||||
 | 
								var af = this.GetExpressionField(select);
 | 
				
			||||||
 | 
								return this.ToSql(af.field);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		protected TReturn InternalToAggregate<TReturn>(Expression select) {
 | 
							protected TReturn InternalToAggregate<TReturn>(Expression select) {
 | 
				
			||||||
			var map = new ReadAnonymousTypeInfo();
 | 
								var map = new ReadAnonymousTypeInfo();
 | 
				
			||||||
@@ -308,7 +311,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			var index = 0;
 | 
								var index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null);
 | 
								_commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null);
 | 
				
			||||||
			return this.ToListMapReader<TReturn>((map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null)).FirstOrDefault();
 | 
								return this.ToListMapReader<TReturn>((map, field.Length > 0 ? field.Remove(0, 2).ToString() : null)).FirstOrDefault();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		async protected Task<TReturn> InternalToAggregateAsync<TReturn>(Expression select) {
 | 
							async protected Task<TReturn> InternalToAggregateAsync<TReturn>(Expression select) {
 | 
				
			||||||
			var map = new ReadAnonymousTypeInfo();
 | 
								var map = new ReadAnonymousTypeInfo();
 | 
				
			||||||
@@ -316,7 +319,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			var index = 0;
 | 
								var index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null);
 | 
								_commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null);
 | 
				
			||||||
			return (await this.ToListMapReaderAsync<TReturn>((map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null))).FirstOrDefault();
 | 
								return (await this.ToListMapReaderAsync<TReturn>((map, field.Length > 0 ? field.Remove(0, 2).ToString() : null))).FirstOrDefault();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		protected TSelect InternalWhere(Expression exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null));
 | 
							protected TSelect InternalWhere(Expression exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
 | 
								_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
 | 
				
			||||||
			var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
								var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
				
			||||||
			method = method.MakeGenericMethod(typeof(TReturn));
 | 
								method = method.MakeGenericMethod(typeof(TReturn));
 | 
				
			||||||
			return method.Invoke(_select, new object[] { (map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null) }) as List<TReturn>;
 | 
								return method.Invoke(_select, new object[] { (map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as List<TReturn>;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		public Task<List<TReturn>> ToListAsync<TReturn>(Expression<Func<ISelectGroupingAggregate<T1>, TReturn>> select) {
 | 
							public Task<List<TReturn>> ToListAsync<TReturn>(Expression<Func<ISelectGroupingAggregate<T1>, TReturn>> select) {
 | 
				
			||||||
			var map = new ReadAnonymousTypeInfo();
 | 
								var map = new ReadAnonymousTypeInfo();
 | 
				
			||||||
@@ -67,7 +67,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
 | 
								_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
 | 
				
			||||||
			var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
								var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
				
			||||||
			method = method.MakeGenericMethod(typeof(TReturn));
 | 
								method = method.MakeGenericMethod(typeof(TReturn));
 | 
				
			||||||
			return method.Invoke(_select, new object[] { (map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null) }) as Task<List<TReturn>>;
 | 
								return method.Invoke(_select, new object[] { (map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as Task<List<TReturn>>;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<T1>, TReturn>> select) {
 | 
							public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<T1>, TReturn>> select) {
 | 
				
			||||||
@@ -77,7 +77,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
 | 
								_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
 | 
				
			||||||
			var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
 | 
								var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
 | 
				
			||||||
			return method.Invoke(_select, new object[] { map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null }) as string;
 | 
								return method.Invoke(_select, new object[] { field.Length > 0 ? field.Remove(0, 2).ToString() : null }) as string;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,10 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		public MySqlExpression(CommonUtils common) : base(common) { }
 | 
							public MySqlExpression(CommonUtils common) : base(common) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal override string ExpressionLambdaToSqlOther(Expression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
							internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
			if (exp.Expression == null) {
 | 
								if (exp.Expression == null) {
 | 
				
			||||||
				switch (exp.Member.Name) {
 | 
									switch (exp.Member.Name) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration;
 | 
				
			|||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.MySql {
 | 
					namespace FreeSql.MySql {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,8 +26,7 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
		public ICache Cache { get; }
 | 
							public ICache Cache { get; }
 | 
				
			||||||
		public ICodeFirst CodeFirst { get; }
 | 
							public ICodeFirst CodeFirst { get; }
 | 
				
			||||||
		public IDbFirst DbFirst { get; }
 | 
							public IDbFirst DbFirst { get; }
 | 
				
			||||||
		public MySqlProvider(IDistributedCache cache, IConfiguration cacheStrategy, string masterConnectionString, string[] slaveConnectionString, ILogger log) {
 | 
							public MySqlProvider(IDistributedCache cache, ILogger log, string masterConnectionString, string[] slaveConnectionString) {
 | 
				
			||||||
			CacheStrategy = cacheStrategy;
 | 
					 | 
				
			||||||
			if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.MySql");
 | 
								if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.MySql");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			this.InternalCommonUtils = new MySqlUtils(this);
 | 
								this.InternalCommonUtils = new MySqlUtils(this);
 | 
				
			||||||
@@ -41,7 +41,6 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		internal CommonUtils InternalCommonUtils { get; }
 | 
							internal CommonUtils InternalCommonUtils { get; }
 | 
				
			||||||
		internal CommonExpression InternalCommonExpression { get; }
 | 
							internal CommonExpression InternalCommonExpression { get; }
 | 
				
			||||||
		internal IConfiguration CacheStrategy { get; private set; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Transaction(Action handler) => Ado.Transaction(handler);
 | 
							public void Transaction(Action handler) => Ado.Transaction(handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,11 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
using Npgsql;
 | 
					using Npgsql;
 | 
				
			||||||
using SafeObjectPool;
 | 
					using SafeObjectPool;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections;
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data.Common;
 | 
					using System.Data.Common;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
@@ -25,6 +27,7 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		static DateTime dt1970 = new DateTime(1970, 1, 1);
 | 
							static DateTime dt1970 = new DateTime(1970, 1, 1);
 | 
				
			||||||
		public override object AddslashesProcessParam(object param) {
 | 
							public override object AddslashesProcessParam(object param) {
 | 
				
			||||||
 | 
								bool isdic = false;
 | 
				
			||||||
			if (param == null) return "NULL";
 | 
								if (param == null) return "NULL";
 | 
				
			||||||
			if (param is bool || param is bool?)
 | 
								if (param is bool || param is bool?)
 | 
				
			||||||
				return (bool)param ? "'t'" : "'f'";
 | 
									return (bool)param ? "'t'" : "'f'";
 | 
				
			||||||
@@ -40,12 +43,25 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
				return ((TimeSpan)param).Ticks / 10;
 | 
									return ((TimeSpan)param).Ticks / 10;
 | 
				
			||||||
			else if (param is TimeSpan?)
 | 
								else if (param is TimeSpan?)
 | 
				
			||||||
				return (param as TimeSpan?).Value.Ticks / 10;
 | 
									return (param as TimeSpan?).Value.Ticks / 10;
 | 
				
			||||||
			else if (param is IEnumerable) {
 | 
								else if (param is JToken || param is JObject || param is JArray)
 | 
				
			||||||
 | 
									return string.Concat("'", param.ToString().Replace("'", "''"), "'::jsonb");
 | 
				
			||||||
 | 
								else if ((isdic = param is Dictionary<string, string>) ||
 | 
				
			||||||
 | 
									param is IEnumerable<KeyValuePair<string, string>>) {
 | 
				
			||||||
 | 
									var pgdics = isdic ? param as Dictionary<string, string> :
 | 
				
			||||||
 | 
										param as IEnumerable<KeyValuePair<string, string>>;
 | 
				
			||||||
 | 
									if (pgdics == null) return string.Concat("''::hstore");
 | 
				
			||||||
 | 
									var pghstore = new StringBuilder();
 | 
				
			||||||
 | 
									pghstore.Append("'");
 | 
				
			||||||
 | 
									foreach (var dic in pgdics)
 | 
				
			||||||
 | 
										pghstore.Append("\"").Append(dic.Key.Replace("'", "''")).Append("\"=>")
 | 
				
			||||||
 | 
											.Append(dic.Key.Replace("'", "''")).Append(",");
 | 
				
			||||||
 | 
									return pghstore.Append("'::hstore");
 | 
				
			||||||
 | 
								} else if (param is IEnumerable) {
 | 
				
			||||||
				var sb = new StringBuilder();
 | 
									var sb = new StringBuilder();
 | 
				
			||||||
				var ie = param as IEnumerable;
 | 
									var ie = param as IEnumerable;
 | 
				
			||||||
				foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z));
 | 
									foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z));
 | 
				
			||||||
				return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString();
 | 
									return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString();
 | 
				
			||||||
			} else {
 | 
								}else {
 | 
				
			||||||
				return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
									return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
				
			||||||
				//if (param is string) return string.Concat('N', nparms[a]);
 | 
									//if (param is string) return string.Concat('N', nparms[a]);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,136 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.PostgreSQL {
 | 
					namespace FreeSql.PostgreSQL {
 | 
				
			||||||
	class PostgreSQLExpression : CommonExpression {
 | 
						class PostgreSQLExpression : CommonExpression {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public PostgreSQLExpression(CommonUtils common) : base(common) { }
 | 
							public PostgreSQLExpression(CommonUtils common) : base(common) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal override string ExpressionLambdaToSqlOther(Expression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								switch (exp.NodeType) {
 | 
				
			||||||
 | 
									case ExpressionType.ArrayLength:
 | 
				
			||||||
 | 
										var arrOperExp = ExpressionLambdaToSql((exp as UnaryExpression).Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
										if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}])";
 | 
				
			||||||
 | 
										return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
 | 
				
			||||||
 | 
									case ExpressionType.Call:
 | 
				
			||||||
 | 
										var callExp = exp as MethodCallExpression;
 | 
				
			||||||
 | 
										var objExp = callExp.Object;
 | 
				
			||||||
 | 
										var objType = objExp?.Type;
 | 
				
			||||||
 | 
										if (objType?.FullName == "System.Byte[]") return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var argIndex = 0;
 | 
				
			||||||
 | 
										if (objType == null && callExp.Method.DeclaringType.FullName == typeof(Enumerable).FullName) {
 | 
				
			||||||
 | 
											objExp = callExp.Arguments.FirstOrDefault();
 | 
				
			||||||
 | 
											objType = objExp?.Type;
 | 
				
			||||||
 | 
											argIndex++;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if (objType == null) objType = callExp.Method.DeclaringType;
 | 
				
			||||||
 | 
										if (objType != null) {
 | 
				
			||||||
 | 
											var left = objExp == null ? null : ExpressionLambdaToSql(objExp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
											if (objType.IsArray == true) {
 | 
				
			||||||
 | 
												if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
												switch (callExp.Method.Name) {
 | 
				
			||||||
 | 
													case "Any": return $"(case when {left} is null then 0 else array_length({left},1) end > 0)";
 | 
				
			||||||
 | 
													case "Contains": return $"({left} @> array[{ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}])";
 | 
				
			||||||
 | 
													case "Concat":
 | 
				
			||||||
 | 
														var right2 = ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
														if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
														return $"({left} || {right2})";
 | 
				
			||||||
 | 
													case "GetLength":
 | 
				
			||||||
 | 
													case "GetLongLength":
 | 
				
			||||||
 | 
													case "Length":
 | 
				
			||||||
 | 
													case "Count": return $"case when {left} is null then 0 else array_length({left},1) end";
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											switch (objType.FullName) {
 | 
				
			||||||
 | 
												case "Newtonsoft.Json.Linq.JToken":
 | 
				
			||||||
 | 
												case "Newtonsoft.Json.Linq.JObject":
 | 
				
			||||||
 | 
												case "Newtonsoft.Json.Linq.JArray":
 | 
				
			||||||
 | 
													switch (callExp.Method.Name) {
 | 
				
			||||||
 | 
														case "Any": return $"(jsonb_array_length(coalesce({left},'[]')) > 0)";
 | 
				
			||||||
 | 
														case "Contains":
 | 
				
			||||||
 | 
															var json = ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
															if (json.StartsWith("'") && json.EndsWith("'")) return $"(coalesce({left},'{{}}') @> {_common.FormatSql("{0}", JToken.Parse(json.Trim('\'')))})";
 | 
				
			||||||
 | 
															return $"(coalesce({left},'{{}}') @> ({json})::jsonb)";
 | 
				
			||||||
 | 
														case "ContainsKey": return $"(coalesce({left},'{{}}') ? {ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})";
 | 
				
			||||||
 | 
														case "Concat":
 | 
				
			||||||
 | 
															var right2 = ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
															return $"(coalesce({left},'{{}}') || {right2})";
 | 
				
			||||||
 | 
														case "LongCount":
 | 
				
			||||||
 | 
														case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
 | 
				
			||||||
 | 
														case "Parse":
 | 
				
			||||||
 | 
															var json2 = ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
															if (json2.StartsWith("'") && json2.EndsWith("'")) return _common.FormatSql("{0}", JToken.Parse(json2.Trim('\'')));
 | 
				
			||||||
 | 
															return $"({json2})::jsonb";
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													break;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											if (objType.FullName == typeof(Dictionary<string, string>).FullName) {
 | 
				
			||||||
 | 
												switch (callExp.Method.Name) {
 | 
				
			||||||
 | 
													case "Contains":
 | 
				
			||||||
 | 
														var right = ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
														return $"({left} @> ({right}))";
 | 
				
			||||||
 | 
													case "ContainsKey": return $"({left} ? {ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})";
 | 
				
			||||||
 | 
													case "Concat": return $"({left} || {ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})";
 | 
				
			||||||
 | 
													case "GetLength":
 | 
				
			||||||
 | 
													case "GetLongLength":
 | 
				
			||||||
 | 
													case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
 | 
				
			||||||
 | 
													case "Keys": return $"akeys({left})";
 | 
				
			||||||
 | 
													case "Values": return $"avals({left})";
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
										var memExp = exp as MemberExpression;
 | 
				
			||||||
 | 
										var memParentExp = memExp.Expression?.Type;
 | 
				
			||||||
 | 
										if (memParentExp?.FullName == "System.Byte[]") return null;
 | 
				
			||||||
 | 
										if (memParentExp != null) {
 | 
				
			||||||
 | 
											var left = ExpressionLambdaToSql(memExp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName);
 | 
				
			||||||
 | 
											if (memParentExp.IsArray == true) {
 | 
				
			||||||
 | 
												if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
												switch (memExp.Member.Name) {
 | 
				
			||||||
 | 
													case "Length":
 | 
				
			||||||
 | 
													case "Count": return $"case when {left} is null then 0 else array_length({left},1) end";
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											switch (memParentExp.FullName) {
 | 
				
			||||||
 | 
												case "Newtonsoft.Json.Linq.JToken":
 | 
				
			||||||
 | 
												case "Newtonsoft.Json.Linq.JObject":
 | 
				
			||||||
 | 
												case "Newtonsoft.Json.Linq.JArray":
 | 
				
			||||||
 | 
													switch (memExp.Member.Name) {
 | 
				
			||||||
 | 
														case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													break;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											if (memParentExp.FullName == typeof(Dictionary<string, string>).FullName) {
 | 
				
			||||||
 | 
												switch (memExp.Member.Name) {
 | 
				
			||||||
 | 
													case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
 | 
				
			||||||
 | 
													case "Keys": return $"akeys({left})";
 | 
				
			||||||
 | 
													case "Values": return $"avals({left})";
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case ExpressionType.NewArrayInit:
 | 
				
			||||||
 | 
										var arrExp = exp as NewArrayExpression;
 | 
				
			||||||
 | 
										var arrSb = new StringBuilder();
 | 
				
			||||||
 | 
										arrSb.Append("array[");
 | 
				
			||||||
 | 
										for (var a = 0; a < arrExp.Expressions.Count; a++) {
 | 
				
			||||||
 | 
											if (a > 0) arrSb.Append(",");
 | 
				
			||||||
 | 
											arrSb.Append(ExpressionLambdaToSql(arrExp.Expressions[a], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return arrSb.Append("]").ToString();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
							internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
			if (exp.Expression == null) {
 | 
								if (exp.Expression == null) {
 | 
				
			||||||
				switch (exp.Member.Name) {
 | 
									switch (exp.Member.Name) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration;
 | 
				
			|||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.PostgreSQL {
 | 
					namespace FreeSql.PostgreSQL {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,8 +26,7 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
		public ICache Cache { get; }
 | 
							public ICache Cache { get; }
 | 
				
			||||||
		public ICodeFirst CodeFirst { get; }
 | 
							public ICodeFirst CodeFirst { get; }
 | 
				
			||||||
		public IDbFirst DbFirst { get; }
 | 
							public IDbFirst DbFirst { get; }
 | 
				
			||||||
		public PostgreSQLProvider(IDistributedCache cache, IConfiguration cacheStrategy, string masterConnectionString, string[] slaveConnectionString, ILogger log) {
 | 
							public PostgreSQLProvider(IDistributedCache cache, ILogger log, string masterConnectionString, string[] slaveConnectionString) {
 | 
				
			||||||
			CacheStrategy = cacheStrategy;
 | 
					 | 
				
			||||||
			if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.PostgreSQL");
 | 
								if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.PostgreSQL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			this.InternalCommonUtils = new PostgreSQLUtils(this);
 | 
								this.InternalCommonUtils = new PostgreSQLUtils(this);
 | 
				
			||||||
@@ -41,7 +41,6 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		internal CommonUtils InternalCommonUtils { get; }
 | 
							internal CommonUtils InternalCommonUtils { get; }
 | 
				
			||||||
		internal CommonExpression InternalCommonExpression { get; }
 | 
							internal CommonExpression InternalCommonExpression { get; }
 | 
				
			||||||
		internal IConfiguration CacheStrategy { get; private set; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Transaction(Action handler) => Ado.Transaction(handler);
 | 
							public void Transaction(Action handler) => Ado.Transaction(handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,10 @@ namespace FreeSql.SqlServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		public SqlServerExpression(CommonUtils common) : base(common) { }
 | 
							public SqlServerExpression(CommonUtils common) : base(common) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal override string ExpressionLambdaToSqlOther(Expression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
							internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
			if (exp.Expression == null) {
 | 
								if (exp.Expression == null) {
 | 
				
			||||||
				switch (exp.Member.Name) {
 | 
									switch (exp.Member.Name) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,8 +25,7 @@ namespace FreeSql.SqlServer {
 | 
				
			|||||||
		public ICache Cache { get; }
 | 
							public ICache Cache { get; }
 | 
				
			||||||
		public ICodeFirst CodeFirst { get; }
 | 
							public ICodeFirst CodeFirst { get; }
 | 
				
			||||||
		public IDbFirst DbFirst { get; }
 | 
							public IDbFirst DbFirst { get; }
 | 
				
			||||||
		public SqlServerProvider(IDistributedCache cache, IConfiguration cacheStrategy, string masterConnectionString, string[] slaveConnectionString, ILogger log) {
 | 
							public SqlServerProvider(IDistributedCache cache, ILogger log, string masterConnectionString, string[] slaveConnectionString) {
 | 
				
			||||||
			CacheStrategy = cacheStrategy;
 | 
					 | 
				
			||||||
			if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.SqlServer");
 | 
								if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.SqlServer");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			this.InternalCommonUtils = new SqlServerUtils(this);
 | 
								this.InternalCommonUtils = new SqlServerUtils(this);
 | 
				
			||||||
@@ -41,7 +40,6 @@ namespace FreeSql.SqlServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		internal CommonUtils InternalCommonUtils { get; }
 | 
							internal CommonUtils InternalCommonUtils { get; }
 | 
				
			||||||
		internal CommonExpression InternalCommonExpression { get; }
 | 
							internal CommonExpression InternalCommonExpression { get; }
 | 
				
			||||||
		internal IConfiguration CacheStrategy { get; private set; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Transaction(Action handler) => Ado.Transaction(handler);
 | 
							public void Transaction(Action handler) => Ado.Transaction(handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,10 @@ IFreeSql fsql = new FreeSql.FreeSqlBuilder()
 | 
				
			|||||||
    .UseConnectionString(FreeSql.DataType.MySql, connstr)
 | 
					    .UseConnectionString(FreeSql.DataType.MySql, connstr)
 | 
				
			||||||
    .UseSlave("connectionString1", "connectionString2") //使用从数据库,支持多个
 | 
					    .UseSlave("connectionString1", "connectionString2") //使用从数据库,支持多个
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .UseMonitorCommand(
 | 
				
			||||||
 | 
					        cmd => Console.WriteLine(cmd.CommandText), //监听SQL命令对象,在执行前
 | 
				
			||||||
 | 
					        (cmd, traceLog) => Console.WriteLine(traceLog)) //监听SQL命令对象,在执行后
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .UseLogger(null) //使用日志,不指定默认输出控制台 ILogger
 | 
					    .UseLogger(null) //使用日志,不指定默认输出控制台 ILogger
 | 
				
			||||||
    .UseCache(null) //使用缓存,不指定默认使用内存 IDistributedCache
 | 
					    .UseCache(null) //使用缓存,不指定默认使用内存 IDistributedCache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user