SQL命令执行监视 + Pgsql表达式(Array/HStore/Jsonb)实现与测试

This commit is contained in:
28810
2018-12-28 18:25:26 +08:00
parent 3ed1213865
commit 43080a4052
18 changed files with 479 additions and 35 deletions

View File

@ -2,6 +2,7 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
namespace FreeSql {
@ -13,6 +14,8 @@ namespace FreeSql {
string[] _slaveConnectionString;
bool _isAutoSyncStructure = false;
bool _isSyncStructureToLower = false;
Action<DbCommand> _aopCommandExecuting = null;
Action<DbCommand, string> _aopCommandExecuted = null;
/// <summary>
/// 使用缓存,不指定默认使用内存
@ -71,17 +74,31 @@ namespace FreeSql {
_isSyncStructureToLower = value;
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() {
IFreeSql ret = null;
switch(_dataType) {
case DataType.MySql: ret = new MySql.MySqlProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger); break;
case DataType.SqlServer: ret = new SqlServer.SqlServerProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger); break;
case DataType.PostgreSQL: ret = new PostgreSQL.PostgreSQLProvider(_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, _logger, _masterConnectionString, _slaveConnectionString); break;
case DataType.PostgreSQL: ret = new PostgreSQL.PostgreSQLProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break;
}
if (ret != null) {
ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure;
ret.CodeFirst.IsSyncStructureToLower = _isSyncStructureToLower;
var ado = ret.Ado as Internal.CommonProvider.AdoProvider;
ado.AopCommandExecuting += _aopCommandExecuting;
ado.AopCommandExecuted += _aopCommandExecuted;
}
return ret;
}

View File

@ -222,6 +222,8 @@ namespace FreeSql.Internal {
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} 解析");
case ExpressionType.MemberAccess:
var exp4 = exp as MemberExpression;
@ -234,6 +236,8 @@ namespace FreeSql.Internal {
case "System.TimeSpan": extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break;
}
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>();
expStack.Push(exp);
@ -341,7 +345,11 @@ namespace FreeSql.Internal {
return $"{alias2}.{name2}";
}
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) {
return _common.IsNull(
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 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 ExpressionLambdaToSqlOther(Expression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName);
}
}

View File

@ -12,6 +12,8 @@ namespace FreeSql.Internal.CommonProvider {
protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex);
protected abstract DbCommand CreateCommand();
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;
@ -32,10 +34,14 @@ namespace FreeSql.Internal.CommonProvider {
if (IsTracePerformance) {
TimeSpan ts = DateTime.Now.Subtract(dt);
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";
foreach (DbParameter parm in cmd.Parameters)
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);
RollbackTransaction();
AopCommandExecuted?.Invoke(cmd, log);
cmd.Parameters.Clear();
if (isThrowException) throw e;
}
@ -261,6 +270,7 @@ namespace FreeSql.Internal.CommonProvider {
AutoCommitTransaction();
if (IsTracePerformance) logtxt += $" AutoCommitTransaction: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
AopCommandExecuting?.Invoke(cmd);
return (tran, cmd);
}
}

View File

@ -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";
AopCommandExecuting?.Invoke(cmd);
return cmd;
}
}

View File

@ -210,13 +210,13 @@ namespace FreeSql.Internal.CommonProvider {
}
return ret;
}
protected (ReadAnonymousTypeInfo map, string field) GetNewExpressionField(NewExpression newexp) {
protected (ReadAnonymousTypeInfo map, string field) GetExpressionField(Expression newexp) {
var map = new ReadAnonymousTypeInfo();
var field = new StringBuilder();
var index = 0;
_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() {
var type = typeof(T1);
@ -281,7 +281,7 @@ namespace FreeSql.Internal.CommonProvider {
var index = -10000; //临时规则,不返回 as1
_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);
}
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 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 Task<List<TReturn>> InternalToListAsync<TReturn>(Expression select) => this.ToListMapReaderAsync<TReturn>(this.GetNewExpressionField(select as NewExpression));
protected string InternalToSql<TReturn>(Expression select) => this.ToSql(this.GetNewExpressionField(select as NewExpression).field);
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.GetExpressionField(select));
protected string InternalToSql<TReturn>(Expression select) {
var af = this.GetExpressionField(select);
return this.ToSql(af.field);
}
protected TReturn InternalToAggregate<TReturn>(Expression select) {
var map = new ReadAnonymousTypeInfo();
@ -308,7 +311,7 @@ namespace FreeSql.Internal.CommonProvider {
var index = 0;
_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) {
var map = new ReadAnonymousTypeInfo();
@ -316,7 +319,7 @@ namespace FreeSql.Internal.CommonProvider {
var index = 0;
_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));

View File

@ -57,7 +57,7 @@ namespace FreeSql.Internal.CommonProvider {
_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
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) {
var map = new ReadAnonymousTypeInfo();
@ -67,7 +67,7 @@ namespace FreeSql.Internal.CommonProvider {
_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
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) {
@ -77,7 +77,7 @@ namespace FreeSql.Internal.CommonProvider {
_comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString);
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;
}

View File

@ -10,6 +10,10 @@ namespace FreeSql.MySql {
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) {
if (exp.Expression == null) {
switch (exp.Member.Name) {

View File

@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data.Common;
namespace FreeSql.MySql {
@ -25,8 +26,7 @@ namespace FreeSql.MySql {
public ICache Cache { get; }
public ICodeFirst CodeFirst { get; }
public IDbFirst DbFirst { get; }
public MySqlProvider(IDistributedCache cache, IConfiguration cacheStrategy, string masterConnectionString, string[] slaveConnectionString, ILogger log) {
CacheStrategy = cacheStrategy;
public MySqlProvider(IDistributedCache cache, ILogger log, string masterConnectionString, string[] slaveConnectionString) {
if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.MySql");
this.InternalCommonUtils = new MySqlUtils(this);
@ -41,7 +41,6 @@ namespace FreeSql.MySql {
internal CommonUtils InternalCommonUtils { get; }
internal CommonExpression InternalCommonExpression { get; }
internal IConfiguration CacheStrategy { get; private set; }
public void Transaction(Action handler) => Ado.Transaction(handler);

View File

@ -1,9 +1,11 @@
using FreeSql.Internal;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using Npgsql;
using SafeObjectPool;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using System.Threading;
@ -25,6 +27,7 @@ namespace FreeSql.PostgreSQL {
}
static DateTime dt1970 = new DateTime(1970, 1, 1);
public override object AddslashesProcessParam(object param) {
bool isdic = false;
if (param == null) return "NULL";
if (param is bool || param is bool?)
return (bool)param ? "'t'" : "'f'";
@ -40,12 +43,25 @@ namespace FreeSql.PostgreSQL {
return ((TimeSpan)param).Ticks / 10;
else if (param is TimeSpan?)
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 ie = param as IEnumerable;
foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z));
return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString();
} else {
}else {
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
//if (param is string) return string.Concat('N', nparms[a]);
}

View File

@ -1,15 +1,136 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace FreeSql.PostgreSQL {
class PostgreSQLExpression : CommonExpression {
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) {
if (exp.Expression == null) {
switch (exp.Member.Name) {

View File

@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data.Common;
namespace FreeSql.PostgreSQL {
@ -25,8 +26,7 @@ namespace FreeSql.PostgreSQL {
public ICache Cache { get; }
public ICodeFirst CodeFirst { get; }
public IDbFirst DbFirst { get; }
public PostgreSQLProvider(IDistributedCache cache, IConfiguration cacheStrategy, string masterConnectionString, string[] slaveConnectionString, ILogger log) {
CacheStrategy = cacheStrategy;
public PostgreSQLProvider(IDistributedCache cache, ILogger log, string masterConnectionString, string[] slaveConnectionString) {
if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.PostgreSQL");
this.InternalCommonUtils = new PostgreSQLUtils(this);
@ -41,7 +41,6 @@ namespace FreeSql.PostgreSQL {
internal CommonUtils InternalCommonUtils { get; }
internal CommonExpression InternalCommonExpression { get; }
internal IConfiguration CacheStrategy { get; private set; }
public void Transaction(Action handler) => Ado.Transaction(handler);

View File

@ -10,6 +10,10 @@ namespace FreeSql.SqlServer {
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) {
if (exp.Expression == null) {
switch (exp.Member.Name) {

View File

@ -25,8 +25,7 @@ namespace FreeSql.SqlServer {
public ICache Cache { get; }
public ICodeFirst CodeFirst { get; }
public IDbFirst DbFirst { get; }
public SqlServerProvider(IDistributedCache cache, IConfiguration cacheStrategy, string masterConnectionString, string[] slaveConnectionString, ILogger log) {
CacheStrategy = cacheStrategy;
public SqlServerProvider(IDistributedCache cache, ILogger log, string masterConnectionString, string[] slaveConnectionString) {
if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.SqlServer");
this.InternalCommonUtils = new SqlServerUtils(this);
@ -41,7 +40,6 @@ namespace FreeSql.SqlServer {
internal CommonUtils InternalCommonUtils { get; }
internal CommonExpression InternalCommonExpression { get; }
internal IConfiguration CacheStrategy { get; private set; }
public void Transaction(Action handler) => Ado.Transaction(handler);