Merge branch 'master' into fix_tree

This commit is contained in:
2881099
2022-04-01 09:02:21 +08:00
committed by GitHub
244 changed files with 28531 additions and 407 deletions

View File

@ -591,6 +591,8 @@ namespace FreeSql.Internal
if (rightExp.Type.NullableTypeOrThis() == typeof(TimeSpan))
return ExpressionLambdaToSql(Expression.Call(leftExp, MethodDateTimeSubtractTimeSpan, rightExp), tsc);
}
if (oper == "OR")
return $"({GetBoolString(ExpressionLambdaToSql(leftExp, tsc))} {oper} {GetBoolString(ExpressionLambdaToSql(rightExp, tsc))})";
return $"({ExpressionLambdaToSql(leftExp, tsc)} {oper} {ExpressionLambdaToSql(rightExp, tsc)})";
case "=":
case "<>":
@ -1011,6 +1013,7 @@ namespace FreeSql.Internal
case DataType.OdbcOracle:
case DataType.Dameng:
case DataType.OdbcDameng:
case DataType.GBase:
break;
default:
fsqlSelect0._limit = 1; //#462 ORACLE rownum <= 2 会影响索引变慢
@ -1065,25 +1068,32 @@ namespace FreeSql.Internal
else
{
var argExp = (arg3Exp as UnaryExpression)?.Operand;
if (argExp != null && argExp.NodeType == ExpressionType.Lambda)
if (argExp != null)
{
if (fsqltable1SetAlias == false)
if (argExp.NodeType == ExpressionType.Lambda)
{
fsqltable1SetAlias = true;
var argExpLambda = argExp as LambdaExpression;
var fsqlTypeGenericArgs = fsqlType.GetGenericArguments();
if (fsqltable1SetAlias == false)
{
fsqltable1SetAlias = true;
var argExpLambda = argExp as LambdaExpression;
var fsqlTypeGenericArgs = fsqlType.GetGenericArguments();
if (argExpLambda.Parameters.Count == 1 && argExpLambda.Parameters[0].Type.FullName.StartsWith("FreeSql.Internal.Model.HzyTuple`"))
{
for (var gai = 0; gai < fsqlTypeGenericArgs.Length; gai++)
fsqltables[gai].Alias = "ht" + (gai + 1);
}
else
{
for (var gai = 0; gai < fsqlTypeGenericArgs.Length && gai < argExpLambda.Parameters.Count; gai++)
fsqltables[gai].Alias = argExpLambda.Parameters[gai].Name;
if (argExpLambda.Parameters.Count == 1 && argExpLambda.Parameters[0].Type.FullName.StartsWith("FreeSql.Internal.Model.HzyTuple`"))
{
for (var gai = 0; gai < fsqlTypeGenericArgs.Length; gai++)
fsqltables[gai].Alias = "ht" + (gai + 1);
}
else
{
for (var gai = 0; gai < fsqlTypeGenericArgs.Length && gai < argExpLambda.Parameters.Count; gai++)
fsqltables[gai].Alias = argExpLambda.Parameters[gai].Name;
}
}
}
else
{
argExp = null;
}
}
args[a] = argExp ?? Expression.Lambda(arg3Exp).Compile().DynamicInvoke();
//if (args[a] == null) ExpressionLambdaToSql(call3Exp.Arguments[a], fsqltables, null, null, SelectTableInfoType.From, true);
@ -1305,6 +1315,7 @@ namespace FreeSql.Internal
{
case DataType.MySql:
case DataType.OdbcMySql:
case DataType.GBase:
if (exp3.Method.Name == "ToList")
return $"( SELECT * FROM ({sqlFirst.Replace(" \r\n", " \r\n ")}) ftblmt50 )";
break;
@ -1876,10 +1887,14 @@ namespace FreeSql.Internal
if (_common.CodeFirst.IsGenerateCommandParameterWithLambda && dbParams != null)
{
if (obj == null) return "NULL";
var paramName = $"exp_{dbParams.Count}";
var parm = _common.AppendParamter(dbParams, paramName, mapColumn,
mapType ?? mapColumn?.Attribute.MapType ?? obj?.GetType(), mapType == null ? obj : Utils.GetDataReaderValue(mapType, obj));
return _common.QuoteParamterName(paramName);
var type = mapType ?? mapColumn?.Attribute.MapType ?? obj?.GetType();
if (_common.CodeFirst.GetDbInfo(type) != null)
{
var paramName = $"exp_{dbParams.Count}";
if (_common._orm?.Ado.DataType == DataType.GBase) paramName = "?";
var parm = _common.AppendParamter(dbParams, paramName, mapColumn, type, mapType == null ? obj : Utils.GetDataReaderValue(mapType, obj));
return _common.QuoteParamterName(paramName);
}
}
return string.Format(CultureInfo.InvariantCulture, "{0}", _ado.AddslashesProcessParam(obj, mapType, mapColumn));
//return string.Concat(_ado.AddslashesProcessParam(obj, mapType, mapColumn));

View File

@ -111,6 +111,7 @@ namespace FreeSql.Internal.CommonProvider
{
case DataType.Oracle:
case DataType.OdbcOracle:
case DataType.GBase:
ExecuteNonQuery(null, null, CommandType.Text, " SELECT 1 FROM dual", commandTimeout);
return true;
case DataType.Firebird:
@ -581,7 +582,20 @@ namespace FreeSql.Internal.CommonProvider
if (availables.Any())
{
isSlave = true;
pool = availables.Count == 1 ? availables[0] : availables[slaveRandom.Next(availables.Count)];
if (availables.Count == 1) pool = availables[0];
else
{
var rnd = slaveRandom.Next(availables.Sum(a => a.Policy.Weight));
for(var a = 0; a < availables.Count; a++)
{
rnd -= availables[a].Policy.Weight;
if (rnd < 0)
{
pool = availables[a];
break;
}
}
}
}
}
}
@ -851,6 +865,7 @@ namespace FreeSql.Internal.CommonProvider
if (cmdParms != null)
{
var dbpool = MasterPool as FreeSql.Internal.CommonProvider.DbConnectionPool;
foreach (var parm in cmdParms)
{
if (parm == null) continue;
@ -871,7 +886,32 @@ namespace FreeSql.Internal.CommonProvider
});
}
}
if (isnew == false) cmd.Parameters.Add(parm);
if (isnew == false)
{
if (dbpool == null) cmd.Parameters.Add(parm);
else
{
var newparm = cmd.CreateParameter(); // UseConnectionFactory 转换 DbParameter
if (newparm.GetType() == parm.GetType()) cmd.Parameters.Add(parm);
else
{
newparm.DbType = parm.DbType;
newparm.Direction = parm.Direction;
newparm.ParameterName = parm.ParameterName;
#if net40 || net45
#else
newparm.Precision = parm.Precision;
newparm.Scale = parm.Scale;
#endif
newparm.Size = parm.Size;
newparm.SourceColumn = parm.SourceColumn;
newparm.SourceColumnNullMapping = parm.SourceColumnNullMapping;
newparm.SourceVersion = parm.SourceVersion;
newparm.Value = parm.Value;
cmd.Parameters.Add(newparm);
}
}
}
}
}

View File

@ -25,6 +25,7 @@ namespace FreeSql.Internal.CommonProvider
{
case DataType.Oracle:
case DataType.OdbcOracle:
case DataType.GBase:
await ExecuteNonQueryAsync(null, null, CommandType.Text, " SELECT 1 FROM dual", commandTimeout, null, cancellationToken);
return true;
case DataType.Firebird:
@ -78,7 +79,7 @@ namespace FreeSql.Internal.CommonProvider
}, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken);
return ret;
}
#region QueryAsync multi
#region QueryAsync multi
public Task<NativeTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync<T1, T2>(null, null, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken);
public Task<NativeTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync<T1, T2>(null, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken);
public Task<NativeTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null, CancellationToken cancellationToken = default) => QueryAsync<T1, T2>(connection, transaction, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken);
@ -468,7 +469,7 @@ namespace FreeSql.Internal.CommonProvider
}, null, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken);
return NativeTuple.Create(ret1, ret2, ret3, ret4, ret5);
}
#endregion
#endregion
public Task ExecuteReaderAsync(Func<FetchCallbackArgs<DbDataReader>, Task> fetchHandler, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, null, fetchHandler, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken);
public Task ExecuteReaderAsync(DbTransaction transaction, Func<FetchCallbackArgs<DbDataReader>, Task> fetchHandler, string cmdText, object parms = null, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, transaction, fetchHandler, CommandType.Text, cmdText, 0, GetDbParamtersByObject(cmdText, parms), cancellationToken);
@ -476,7 +477,7 @@ namespace FreeSql.Internal.CommonProvider
public Task ExecuteReaderAsync(Func<FetchCallbackArgs<DbDataReader>, Task> fetchHandler, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, null, fetchHandler, cmdType, cmdText, 0, cmdParms, cancellationToken);
public Task ExecuteReaderAsync(DbTransaction transaction, Func<FetchCallbackArgs<DbDataReader>, Task> fetchHandler, CommandType cmdType, string cmdText, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteReaderAsync(null, transaction, fetchHandler, cmdType, cmdText, 0, cmdParms, cancellationToken);
public Task ExecuteReaderAsync(DbConnection connection, DbTransaction transaction, Func<FetchCallbackArgs<DbDataReader>, Task> fetchHandler, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default) => ExecuteReaderMultipleAsync(1, connection, transaction, (fetch, result) => fetchHandler(fetch), null, cmdType, cmdText, cmdTimeout, cmdParms, cancellationToken);
public async Task ExecuteReaderMultipleAsync(int multipleResult, DbConnection connection, DbTransaction transaction, Func<FetchCallbackArgs<DbDataReader>, int, Task> fetchHandler, Action<DbDataReader, int> schemaHandler, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default)
async public Task ExecuteReaderMultipleAsync(int multipleResult, DbConnection connection, DbTransaction transaction, Func<FetchCallbackArgs<DbDataReader>, int, Task> fetchHandler, Action<DbDataReader, int> schemaHandler, CommandType cmdType, string cmdText, int cmdTimeout, DbParameter[] cmdParms, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(cmdText)) return;
var dt = DateTime.Now;
@ -756,6 +757,7 @@ namespace FreeSql.Internal.CommonProvider
if (cmdParms != null)
{
var dbpool = MasterPool as FreeSql.Internal.CommonProvider.DbConnectionPool;
foreach (var parm in cmdParms)
{
if (parm == null) continue;
@ -776,7 +778,32 @@ namespace FreeSql.Internal.CommonProvider
});
}
}
if (isnew == false) cmd.Parameters.Add(parm);
if (isnew == false)
{
if (dbpool == null) cmd.Parameters.Add(parm);
else
{
var newparm = cmd.CreateParameter(); // UseConnectionFactory 转换 DbParameter
if (newparm.GetType() == parm.GetType()) cmd.Parameters.Add(parm);
else
{
newparm.DbType = parm.DbType;
newparm.Direction = parm.Direction;
newparm.ParameterName = parm.ParameterName;
#if net40 || net45
#else
newparm.Precision = parm.Precision;
newparm.Scale = parm.Scale;
#endif
newparm.Size = parm.Size;
newparm.SourceColumn = parm.SourceColumn;
newparm.SourceColumnNullMapping = parm.SourceColumnNullMapping;
newparm.SourceVersion = parm.SourceVersion;
newparm.Value = parm.Value;
cmd.Parameters.Add(newparm);
}
}
}
}
}

View File

@ -110,6 +110,7 @@ namespace FreeSql.Internal.CommonProvider
public bool IsThrowGetTimeoutException { get; set; } = true;
public bool IsAutoDisposeWithSystem { get; set; } = true;
public int CheckAvailableInterval { get; set; } = 5;
public int Weight { get; set; } = 1;
public DbConnection OnCreate()
{

View File

@ -15,7 +15,11 @@ namespace FreeSql.Internal.CommonProvider
public ISelect<T1> Select<T1>() where T1 : class => CreateSelectProvider<T1>(null);
public ISelect<T1> Select<T1>(object dywhere) where T1 : class => CreateSelectProvider<T1>(dywhere);
public IInsert<T1> Insert<T1>() where T1 : class => CreateInsertProvider<T1>();
public IInsert<T1> Insert<T1>() where T1 : class
{
if (typeof(T1) == typeof(Dictionary<string, object>)) throw new Exception("请使用 fsql.InsertDict(dict) 方法插入字典数据");
return CreateInsertProvider<T1>();
}
public IInsert<T1> Insert<T1>(T1 source) where T1 : class => this.Insert<T1>().AppendData(source);
public IInsert<T1> Insert<T1>(T1[] source) where T1 : class => this.Insert<T1>().AppendData(source);
public IInsert<T1> Insert<T1>(List<T1> source) where T1 : class => this.Insert<T1>().AppendData(source);

View File

@ -94,7 +94,7 @@ namespace FreeSql.Internal.CommonProvider
protected void SyncStructure(params TypeAndName[] objects)
{
if (objects == null) return;
var syncObjects = objects.Where(a => a.entityType != typeof(object) && _dicSycedGetOrAdd(a.entityType).ContainsKey(GetTableNameLowerOrUpper(a.tableName)) == false && GetTableByEntity(a.entityType)?.DisableSyncStructure == false)
var syncObjects = objects.Where(a => a.entityType != null && a.entityType != typeof(object) && _dicSycedGetOrAdd(a.entityType).ContainsKey(GetTableNameLowerOrUpper(a.tableName)) == false && GetTableByEntity(a.entityType)?.DisableSyncStructure == false)
.Select(a => new TypeAndName(a.entityType, GetTableNameLowerOrUpper(a.tableName))).ToArray();
if (syncObjects.Any() == false) return;
var before = new Aop.SyncStructureBeforeEventArgs(syncObjects.Select(a => a.entityType).ToArray());

View File

@ -147,6 +147,11 @@ namespace FreeSql.Internal.CommonProvider
_tableRule = tableRule;
return this;
}
public IDelete<T1> AsTable(string tableName)
{
_tableRule = (oldname) => tableName;
return this;
}
public IDelete<T1> AsType(Type entityType)
{
if (entityType == typeof(object)) throw new Exception("IDelete.AsType 参数不支持指定为 object");
@ -157,7 +162,7 @@ namespace FreeSql.Internal.CommonProvider
return this;
}
public string ToSql()
public virtual string ToSql()
{
if (_whereTimes <= 0) return null;
var sb = new StringBuilder().Append("DELETE FROM ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" WHERE ").Append(_where);

View File

@ -29,7 +29,7 @@ namespace FreeSql.Internal.CommonProvider
public DbTransaction _transaction;
public DbConnection _connection;
public int _commandTimeout = 0;
public ColumnInfo IdentityColumn { get; }
public ColumnInfo IdentityColumn { get; private set; }
public InsertOrUpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
@ -37,12 +37,10 @@ namespace FreeSql.Internal.CommonProvider
_commonUtils = commonUtils;
_commonExpression = commonExpression;
_table = _commonUtils.GetTableByEntity(typeof(T1));
if (_table == null)
{
if (_table == null && typeof(T1) != typeof(Dictionary<string, object>))
throw new Exception($"InsertOrUpdate<>的泛型参数 不支持 {typeof(T1)},请传递您的实体类");
}
if (_orm.CodeFirst.IsAutoSyncStructure && typeof(T1) != typeof(object)) _orm.CodeFirst.SyncStructure<T1>();
IdentityColumn = _table.Primarys.Where(a => a.Attribute.IsIdentity).FirstOrDefault();
IdentityColumn = _table?.Primarys.Where(a => a.Attribute.IsIdentity).FirstOrDefault();
}
protected void ClearData()
@ -88,14 +86,14 @@ namespace FreeSql.Internal.CommonProvider
}
public static void AuditDataValue(object sender, T1 data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict)
{
if (data == null) return;
if (data == null || table == null) return;
if (typeof(T1) == typeof(object) && new[] { table.Type, table.TypeLazy }.Contains(data.GetType()) == false)
throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。");
if (orm.Aop.AuditValueHandler == null) return;
foreach (var col in table.Columns.Values)
{
object val = col.GetValue(data);
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.InsertOrUpdate, col, table.Properties[col.CsName], val);
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.InsertOrUpdate, col, table.Properties.TryGetValue(col.CsName, out var tryprop) ? tryprop : null, val);
orm.Aop.AuditValueHandler(sender, auditArgs);
if (auditArgs.ValueIsChanged)
{
@ -112,6 +110,7 @@ namespace FreeSql.Internal.CommonProvider
public IInsertOrUpdate<T1> SetSource(IEnumerable<T1> source)
{
if (source == null || source.Any() == false) return this;
UpdateProvider<T1>.GetDictionaryTableInfo(source.FirstOrDefault(), _orm, ref _table);
AuditDataValue(this, source, _orm, _table, _auditValueChangedDict);
_source.AddRange(source.Where(a => a != null));
return this;
@ -139,6 +138,11 @@ namespace FreeSql.Internal.CommonProvider
_tableRule = tableRule;
return this;
}
public IInsertOrUpdate<T1> AsTable(string tableName)
{
_tableRule = (oldname) => tableName;
return this;
}
public IInsertOrUpdate<T1> AsType(Type entityType)
{
if (entityType == typeof(object)) throw new Exception("IInsertOrUpdate.AsType 参数不支持指定为 object");
@ -146,6 +150,7 @@ namespace FreeSql.Internal.CommonProvider
var newtb = _commonUtils.GetTableByEntity(entityType);
_table = newtb ?? throw new Exception("IInsertOrUpdate.AsType 参数错误,请传入正确的实体类型");
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(entityType);
IdentityColumn = _table.Primarys.Where(a => a.Attribute.IsIdentity).FirstOrDefault();
return this;
}
@ -182,6 +187,7 @@ namespace FreeSql.Internal.CommonProvider
case DataType.Oracle:
case DataType.OdbcDameng:
case DataType.Dameng:
case DataType.GBase:
sb.Append(" FROM dual");
break;
case DataType.Firebird:

View File

@ -9,6 +9,7 @@ using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace FreeSql.Internal.CommonProvider
{
@ -115,6 +116,7 @@ namespace FreeSql.Internal.CommonProvider
{
if (source != null)
{
UpdateProvider<T1>.GetDictionaryTableInfo(source, _orm, ref _table);
AuditDataValue(this, source, _orm, _table, _auditValueChangedDict);
_source.Add(source);
}
@ -124,6 +126,7 @@ namespace FreeSql.Internal.CommonProvider
{
if (source != null)
{
UpdateProvider<T1>.GetDictionaryTableInfo(source.FirstOrDefault(), _orm, ref _table);
AuditDataValue(this, source, _orm, _table, _auditValueChangedDict);
_source.AddRange(source);
}
@ -134,6 +137,7 @@ namespace FreeSql.Internal.CommonProvider
if (source != null)
{
source = source.Where(a => a != null).ToList();
UpdateProvider<T1>.GetDictionaryTableInfo(source.FirstOrDefault(), _orm, ref _table);
AuditDataValue(this, source, _orm, _table, _auditValueChangedDict);
_source.AddRange(source);
@ -148,7 +152,7 @@ namespace FreeSql.Internal.CommonProvider
}
public static void AuditDataValue(object sender, T1 data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict)
{
if (data == null) return;
if (data == null || table == null) return;
if (typeof(T1) == typeof(object) && new[] { table.Type, table.TypeLazy }.Contains(data.GetType()) == false)
throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。");
foreach (var col in table.Columns.Values)
@ -156,7 +160,7 @@ namespace FreeSql.Internal.CommonProvider
object val = col.GetValue(data);
if (orm.Aop.AuditValueHandler != null)
{
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.Insert, col, table.Properties[col.CsName], val);
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.Insert, col, table.Properties.TryGetValue(col.CsName, out var tryprop) ? tryprop : null, val);
orm.Aop.AuditValueHandler(sender, auditArgs);
if (auditArgs.ValueIsChanged)
{
@ -210,7 +214,7 @@ namespace FreeSql.Internal.CommonProvider
ret[a] = _source.GetRange(a * takeMax, Math.Min(takeMax, _source.Count - a * takeMax));
return ret;
}
protected int SplitExecuteAffrows(int valuesLimit, int parameterLimit)
protected virtual int SplitExecuteAffrows(int valuesLimit, int parameterLimit)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = 0;
@ -505,13 +509,14 @@ namespace FreeSql.Internal.CommonProvider
protected string TableRuleInvoke()
{
if (_tableRule == null) return _table.DbName;
var newname = _tableRule(_table.DbName);
if (newname == _table.DbName) return _table.DbName;
if (string.IsNullOrEmpty(newname)) return _table.DbName;
var tbname = _table?.DbName ?? "";
if (_tableRule == null) return tbname;
var newname = _tableRule(tbname);
if (newname == tbname) return tbname;
if (string.IsNullOrEmpty(newname)) return tbname;
if (_orm.CodeFirst.IsSyncStructureToLower) newname = newname.ToLower();
if (_orm.CodeFirst.IsSyncStructureToUpper) newname = newname.ToUpper();
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(_table.Type, newname);
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(_table?.Type, newname);
return newname;
}
public IInsert<T1> AsTable(Func<string, string> tableRule)
@ -519,6 +524,11 @@ namespace FreeSql.Internal.CommonProvider
_tableRule = tableRule;
return this;
}
public IInsert<T1> AsTable(string tableName)
{
_tableRule = (oldname) => tableName;
return this;
}
public IInsert<T1> AsType(Type entityType)
{
if (entityType == typeof(object)) throw new Exception("IInsert.AsType 参数不支持指定为 object");

View File

@ -17,7 +17,7 @@ namespace FreeSql.Internal.CommonProvider
{
#if net40
#else
async protected Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
async protected virtual Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = 0;
@ -96,7 +96,7 @@ namespace FreeSql.Internal.CommonProvider
return ret;
}
async protected Task<long> SplitExecuteIdentityAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
async protected virtual Task<long> SplitExecuteIdentityAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
long ret = 0;
@ -177,7 +177,7 @@ namespace FreeSql.Internal.CommonProvider
return ret;
}
async protected Task<List<T1>> SplitExecuteInsertedAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
async protected virtual Task<List<T1>> SplitExecuteInsertedAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = new List<T1>();

View File

@ -352,6 +352,7 @@ namespace FreeSql.Internal.CommonProvider
case DataType.Oracle:
case DataType.OdbcOracle:
case DataType.Firebird:
case DataType.GBase:
break;
default:
_select = "SELECT ";
@ -407,6 +408,7 @@ namespace FreeSql.Internal.CommonProvider
case DataType.Oracle:
case DataType.OdbcOracle:
case DataType.Firebird:
case DataType.GBase:
break;
default:
var beforeSql = this._select;
@ -440,6 +442,7 @@ namespace FreeSql.Internal.CommonProvider
case DataType.Oracle:
case DataType.OdbcOracle:
case DataType.Firebird:
case DataType.GBase:
break;
default:
var beforeSql = this._select;
@ -544,17 +547,35 @@ namespace FreeSql.Internal.CommonProvider
{
if (string.IsNullOrEmpty(fi.Field) == false)
{
Expression exp = ConvertStringPropertyToExpression(fi.Field);
Expression exp = null;
switch (fi.Operator)
{
case DynamicFilterOperator.Custom:
var fiValueCustomArray = fi.Field?.ToString().Split(new[] { ' ' }, 2);
if (fiValueCustomArray.Length != 2) throw new ArgumentException("Custom 要求 Field 应该空格分割,并且长度为 2格式{静态方法名}{空格}{反射信息}");
if (string.IsNullOrWhiteSpace(fiValueCustomArray[0])) throw new ArgumentException("Custom {静态方法名}不能为空,格式:{静态方法名}{空格}{反射信息}");
if (string.IsNullOrWhiteSpace(fiValueCustomArray[1])) throw new ArgumentException("Custom {反射信息}不能为空,格式:{静态方法名}{空格}{反射信息}");
var fiValue1Type = Type.GetType(fiValueCustomArray[1]);
if (fiValue1Type == null) throw new ArgumentException($"Custom 找不到对应的{{反射信息}}{fiValueCustomArray[1]}");
var fiValue0Method = fiValue1Type.GetMethod(fiValueCustomArray[0], new Type[] { typeof(string) });
if (fiValue0Method == null) throw new ArgumentException($"Custom 找不到对应的{{静态方法名}}{fiValueCustomArray[0]}");
if (MethodIsDynamicFilterCustomAttribute(fiValue0Method) == false) throw new ArgumentException($"Custom 对应的{{静态方法名}}{fiValueCustomArray[0]} 未设置 [DynamicFilterCustomAttribute] 特性");
var fiValue0MethodReturn = fiValue0Method?.Invoke(null, new object[] { fi.Value?.ToString() })?.ToString();
exp = Expression.Call(typeof(SqlExt).GetMethod("InternalRawSql", BindingFlags.NonPublic | BindingFlags.Static), Expression.Constant(fiValue0MethodReturn, typeof(string)));
break;
case DynamicFilterOperator.Contains:
case DynamicFilterOperator.StartsWith:
case DynamicFilterOperator.EndsWith:
case DynamicFilterOperator.NotContains:
case DynamicFilterOperator.NotStartsWith:
case DynamicFilterOperator.NotEndsWith:
exp = ConvertStringPropertyToExpression(fi.Field);
if (exp.Type != typeof(string)) exp = Expression.TypeAs(exp, typeof(string));
break;
default:
exp = ConvertStringPropertyToExpression(fi.Field);
break;
}
switch (fi.Operator)
{
@ -579,7 +600,7 @@ namespace FreeSql.Internal.CommonProvider
if (fiValueRangeArray.Length != 2) throw new ArgumentException($"Range 要求 Value 应该逗号分割,并且长度为 2");
exp = Expression.AndAlso(
Expression.GreaterThanOrEqual(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueRangeArray[0]), exp.Type)),
Expression.LessThan(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueRangeArray[1]), exp.Type)));
Expression.LessThan(exp, Expression.Constant(Utils.GetDataReaderValue(exp.Type, fiValueRangeArray[1]), exp.Type)));
break;
case DynamicFilterOperator.DateRange:
var fiValueDateRangeArray = getFiListValue();
@ -676,6 +697,21 @@ namespace FreeSql.Internal.CommonProvider
string.IsNullOrEmpty(testFilter.Value?.ToString());
}
}
static ConcurrentDictionary<MethodInfo, bool> _dicMethodIsDynamicFilterCustomAttribute = new ConcurrentDictionary<MethodInfo, bool>();
static bool MethodIsDynamicFilterCustomAttribute(MethodInfo method) => _dicMethodIsDynamicFilterCustomAttribute.GetOrAdd(method, m =>
{
object[] attrs = null;
try
{
attrs = m.GetCustomAttributes(false).ToArray(); //.net core 反射存在版本冲突问题,导致该方法异常
}
catch { }
var dyattr = attrs?.Where(a => {
return ((a as Attribute)?.TypeId as Type)?.Name == "DynamicFilterCustomAttribute";
}).FirstOrDefault();
return dyattr != null;
});
public TSelect DisableGlobalFilter(params string[] name)
{
@ -722,6 +758,7 @@ namespace FreeSql.Internal.CommonProvider
break;
case DataType.Sqlite:
break;
case DataType.GBase:
case DataType.ShenTong: //神通测试中发现,不支持 nowait
_tosqlAppendContent = $"{_tosqlAppendContent} for update";
break;

View File

@ -19,6 +19,25 @@ namespace FreeSql.Internal.CommonProvider
{
partial class Select0Provider<TSelect, T1>
{
public DataTable ToDataTableByPropertyName(string[] properties)
{
if (properties?.Any() != true) throw new ArgumentException($"properties 参数不能为空");
var sbfield = new StringBuilder();
for (var propIdx = 0; propIdx < properties.Length; propIdx++)
{
var property = properties[propIdx];
var exp = ConvertStringPropertyToExpression(property);
if (exp == null) throw new Exception($"{property} 属性名无法找到");
var field = _commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null);
if (propIdx > 0) sbfield.Append(", ");
sbfield.Append(field);
//if (field != property)
sbfield.Append(_commonUtils.FieldAsAlias(_commonUtils.QuoteSqlName("test").Replace("test", property)));
}
var sbfieldStr = sbfield.ToString();
sbfield.Clear();
return ToDataTable(sbfieldStr);
}
public DataTable ToDataTable(string field = null)
{
DataTable ret = null;
@ -514,7 +533,7 @@ namespace FreeSql.Internal.CommonProvider
});
}
static EventHandler<Aop.AuditDataReaderEventArgs> _OldAuditDataReaderHandler;
public GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevel2()
public GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevel2(bool isRereadSql = true)
{
if (_selectExpression != null) //ToSql
{
@ -530,7 +549,7 @@ namespace FreeSql.Internal.CommonProvider
_OldAuditDataReaderHandler = _orm.Aop.AuditDataReaderHandler; //清除单表 ExppressionTree
_dicGetAllFieldExpressionTree.TryRemove($"{_orm.Ado.DataType}-{_tables[0].Table.DbName}-{_tables[0].Table.Type.FullName}-{_tables[0].Alias}-{_tables[0].Type}", out var oldet);
}
return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Table.Type.FullName}-{a.Alias}-{a.Type}")), s =>
return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Table.Type.FullName}-{a.Alias}-{a.Type}-{(isRereadSql ? 1 : 0)}")), s =>
{
var tb1 = _tables.First().Table;
var type = tb1.TypeLazy ?? tb1.Type;
@ -564,7 +583,8 @@ namespace FreeSql.Internal.CommonProvider
{ //普通字段
if (index > 0) field.Append(", ");
var quoteName = _commonUtils.QuoteSqlName(col.Attribute.Name);
field.Append(_commonUtils.RereadColumn(col, $"{tb.Alias}.{quoteName}"));
if (isRereadSql) field.Append(_commonUtils.RereadColumn(col, $"{tb.Alias}.{quoteName}"));
else field.Append($"{tb.Alias}.{quoteName}");
++index;
if (dicfield.ContainsKey(quoteName)) field.Append(_commonUtils.FieldAsAlias($"as{index}"));
else dicfield.Add(quoteName, true);
@ -587,7 +607,8 @@ namespace FreeSql.Internal.CommonProvider
{
if (index > 0) field.Append(", ");
var quoteName = _commonUtils.QuoteSqlName(col2.Attribute.Name);
field.Append(_commonUtils.RereadColumn(col2, $"{tb2.Alias}.{quoteName}"));
if (isRereadSql) field.Append(_commonUtils.RereadColumn(col2, $"{tb2.Alias}.{quoteName}"));
else field.Append($"{tb2.Alias}.{quoteName}");
++index;
++otherindex;
if (dicfield.ContainsKey(quoteName)) field.Append(_commonUtils.FieldAsAlias($"as{index}"));
@ -760,8 +781,32 @@ namespace FreeSql.Internal.CommonProvider
_commonExpression.ExpressionJoinLambda(_tables, joinType, exp, null, _whereGlobalFilter);
return this as TSelect;
}
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 InternalOrderBy(Expression column)
{
if (column.NodeType == ExpressionType.Lambda) column = (column as LambdaExpression)?.Body;
switch (column?.NodeType)
{
case ExpressionType.New:
var newExp = column as NewExpression;
if (newExp == null) break;
for (var a = 0; a < newExp.Members.Count; a++) this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, newExp.Arguments[a], true, null));
return this as TSelect;
}
return this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null));
}
protected TSelect InternalOrderByDescending(Expression column)
{
if (column.NodeType == ExpressionType.Lambda) column = (column as LambdaExpression)?.Body;
switch (column?.NodeType)
{
case ExpressionType.New:
var newExp = column as NewExpression;
if (newExp == null) break;
for (var a = 0; a < newExp.Members.Count; a++) this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, newExp.Arguments[a], true, null)} DESC");
return this as TSelect;
}
return this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC");
}
public List<TReturn> InternalToList<TReturn>(Expression select) => this.ToListMapReader<TReturn>(this.GetExpressionField(select));
protected string InternalToSql<TReturn>(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
@ -876,6 +921,25 @@ namespace FreeSql.Internal.CommonProvider
#region Async
#if net40
#else
public Task<DataTable> ToDataTableByPropertyNameAsync(string[] properties, CancellationToken cancellationToken)
{
if (properties?.Any() != true) throw new ArgumentException($"properties 参数不能为空");
var sbfield = new StringBuilder();
for (var propIdx = 0; propIdx < properties.Length; propIdx++)
{
var property = properties[propIdx];
var exp = ConvertStringPropertyToExpression(property);
if (exp == null) throw new Exception($"{property} 属性名无法找到");
var field = _commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null);
if (propIdx > 0) sbfield.Append(", ");
sbfield.Append(field);
//if (field != property)
sbfield.Append(_commonUtils.FieldAsAlias(_commonUtils.QuoteSqlName("test").Replace("test", property)));
}
var sbfieldStr = sbfield.ToString();
sbfield.Clear();
return ToDataTableAsync(sbfieldStr, cancellationToken);
}
async public Task<DataTable> ToDataTableAsync(string field, CancellationToken cancellationToken)
{
DataTable ret = null;

View File

@ -96,6 +96,15 @@ namespace FreeSql.Internal.CommonProvider
}
public void InternalOrderBy(Expression exp, bool isDescending)
{
if (exp.NodeType == ExpressionType.Lambda) exp = (exp as LambdaExpression)?.Body;
if (exp?.NodeType == ExpressionType.New)
{
var newExp = exp as NewExpression;
if (newExp != null)
for (var a = 0; a < newExp.Members.Count; a++)
InternalOrderBy(newExp.Arguments[a], isDescending);
return;
}
var sql = _comonExp.ExpressionWhereLambda(null, exp, this, null, null);
var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) });
method.Invoke(_select, new object[] { isDescending ? $"{sql} DESC" : sql, null });
@ -150,6 +159,7 @@ namespace FreeSql.Internal.CommonProvider
case DataType.OdbcOracle:
case DataType.Dameng:
case DataType.OdbcDameng: //Oracle、Dameng 分组时,嵌套分页
case DataType.GBase:
isNestedPageSql = true;
break;
default:

View File

@ -46,7 +46,7 @@ namespace FreeSql.Internal.CommonProvider
_commonUtils = commonUtils;
_commonExpression = commonExpression;
_table = _commonUtils.GetTableByEntity(typeof(T1));
_tempPrimarys = _table.Primarys;
_tempPrimarys = _table?.Primarys ?? new ColumnInfo[0];
_noneParameter = _orm.CodeFirst.IsNoneCommandParameter;
this.Where(_commonUtils.WhereObject(_table, "", dywhere));
if (_orm.CodeFirst.IsAutoSyncStructure && typeof(T1) != typeof(object)) _orm.CodeFirst.SyncStructure<T1>();
@ -60,7 +60,7 @@ namespace FreeSql.Internal.CommonProvider
protected void IgnoreCanUpdate()
{
if (_table == null || _table.Type == typeof(object)) return;
foreach (var col in _table.Columns.Values)
foreach (var col in _table?.Columns.Values)
if (col.Attribute.CanUpdate == false && _ignore.ContainsKey(col.Attribute.Name) == false)
_ignore.Add(col.Attribute.Name, true);
}
@ -138,7 +138,7 @@ namespace FreeSql.Internal.CommonProvider
}
#region values数量限制
internal List<T1>[] SplitSource(int valuesLimit, int parameterLimit)
protected internal List<T1>[] SplitSource(int valuesLimit, int parameterLimit)
{
valuesLimit = valuesLimit - 1;
parameterLimit = parameterLimit - 1;
@ -163,7 +163,7 @@ namespace FreeSql.Internal.CommonProvider
ret[a] = _source.GetRange(a * takeMax, Math.Min(takeMax, _source.Count - a * takeMax));
return ret;
}
protected int SplitExecuteAffrows(int valuesLimit, int parameterLimit)
protected virtual int SplitExecuteAffrows(int valuesLimit, int parameterLimit)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = 0;
@ -237,7 +237,7 @@ namespace FreeSql.Internal.CommonProvider
return ret;
}
protected List<T1> SplitExecuteUpdated(int valuesLimit, int parameterLimit)
protected virtual List<T1> SplitExecuteUpdated(int valuesLimit, int parameterLimit)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = new List<T1>();
@ -377,7 +377,7 @@ namespace FreeSql.Internal.CommonProvider
foreach (var col in table.Columns.Values)
{
object val = col.GetValue(d);
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.Update, col, table.Properties[col.CsName], val);
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.Update, col, table.Properties.TryGetValue(col.CsName, out var tryprop) ? tryprop : null, val);
orm.Aop.AuditValueHandler(sender, auditArgs);
if (auditArgs.ValueIsChanged)
{
@ -393,13 +393,13 @@ namespace FreeSql.Internal.CommonProvider
public static void AuditDataValue(object sender, T1 data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict)
{
if (orm.Aop.AuditValueHandler == null) return;
if (data == null) return;
if (data == null || table == null) return;
if (typeof(T1) == typeof(object) && new[] { table.Type, table.TypeLazy }.Contains(data.GetType()) == false)
throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。");
foreach (var col in table.Columns.Values)
{
object val = col.GetValue(data);
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.Update, col, table.Properties[col.CsName], val);
var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.Update, col, table.Properties.TryGetValue(col.CsName, out var tryprop) ? tryprop : null, val);
orm.Aop.AuditValueHandler(sender, auditArgs);
if (auditArgs.ValueIsChanged)
{
@ -412,10 +412,49 @@ namespace FreeSql.Internal.CommonProvider
}
}
public static void GetDictionaryTableInfo(T1 source, IFreeSql orm, ref TableInfo table)
{
if (table == null && typeof(T1) == typeof(Dictionary<string, object>))
{
if (source == null) throw new ArgumentNullException(nameof(source));
var dic = source as Dictionary<string, object>;
table = new TableInfo();
table.Type = typeof(Dictionary<string, object>);
table.CsName = dic.TryGetValue("", out var tryval) ? string.Concat(tryval) : "";
table.DbName = table.CsName;
table.DisableSyncStructure = true;
table.IsDictionaryType = true;
var colpos = new List<ColumnInfo>();
foreach (var kv in dic)
{
var colName = kv.Key;
if (orm.CodeFirst.IsSyncStructureToLower) colName = colName.ToLower();
if (orm.CodeFirst.IsSyncStructureToUpper) colName = colName.ToUpper();
var col = new ColumnInfo
{
CsName = kv.Key,
Table = table,
Attribute = new DataAnnotations.ColumnAttribute
{
Name = colName,
MapType = typeof(object)
},
CsType = typeof(object)
};
table.Columns.Add(colName, col);
table.ColumnsByCs.Add(kv.Key, col);
colpos.Add(col);
}
table.ColumnsByPosition = colpos.ToArray();
colpos.Clear();
}
}
public IUpdate<T1> SetSource(T1 source) => this.SetSource(new[] { source });
public IUpdate<T1> SetSource(IEnumerable<T1> source, Expression<Func<T1, object>> tempPrimarys = null)
{
if (source == null || source.Any() == false) return this;
GetDictionaryTableInfo(source.FirstOrDefault(), _orm, ref _table);
AuditDataValue(this, source, _orm, _table, _auditValueChangedDict);
_source.AddRange(source.Where(a => a != null));
@ -445,7 +484,7 @@ namespace FreeSql.Internal.CommonProvider
_set.Append(", ").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ");
var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(_params, "u", col, col.Attribute.MapType, val) :
_commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, $"{_commonUtils.QuoteParamterName("p_")}{_params.Count}");
_commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"p_{_params.Count}"));
_set.Append(_commonUtils.RewriteColumn(col, colsql));
if (_noneParameter == false)
_commonUtils.AppendParamter(_params, null, col, col.Attribute.MapType, val);
@ -487,7 +526,8 @@ namespace FreeSql.Internal.CommonProvider
var memberName = initExp.Bindings[a].Member.Name;
if (_table.ColumnsByCsIgnore.ContainsKey(memberName)) continue;
if (_table.ColumnsByCs.TryGetValue(memberName, out var col) == false) throw new Exception($"找不到属性:{memberName}");
var memberValue = _commonExpression.ExpressionLambdaToSql(initAssignExp.Expression, new CommonExpression.ExpTSC { isQuoteName = true, mapType = col.Attribute.MapType });
var memberValue = _commonExpression.ExpressionLambdaToSql(initAssignExp.Expression, new CommonExpression.ExpTSC { isQuoteName = true,
mapType = initAssignExp.Expression is BinaryExpression ? null : col.Attribute.MapType });
_setIncr.Append(", ").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(memberValue);
}
}
@ -501,7 +541,8 @@ namespace FreeSql.Internal.CommonProvider
var memberName = newExp.Members[a].Name;
if (_table.ColumnsByCsIgnore.ContainsKey(memberName)) continue;
if (_table.ColumnsByCs.TryGetValue(memberName, out var col) == false) throw new Exception($"找不到属性:{memberName}");
var memberValue = _commonExpression.ExpressionLambdaToSql(newExp.Arguments[a], new CommonExpression.ExpTSC { isQuoteName = true, mapType = col.Attribute.MapType });
var memberValue = _commonExpression.ExpressionLambdaToSql(newExp.Arguments[a], new CommonExpression.ExpTSC { isQuoteName = true,
mapType = newExp.Arguments[a] is BinaryExpression ? null : col.Attribute.MapType });
_setIncr.Append(", ").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(memberValue);
}
}
@ -665,6 +706,11 @@ namespace FreeSql.Internal.CommonProvider
_tableRule = tableRule;
return this;
}
public IUpdate<T1> AsTable(string tableName)
{
_tableRule = (oldname) => tableName;
return this;
}
public IUpdate<T1> AsType(Type entityType)
{
if (entityType == typeof(object)) throw new Exception("IUpdate.AsType 参数不支持指定为 object");

View File

@ -18,7 +18,7 @@ namespace FreeSql.Internal.CommonProvider
{
#if net40
#else
async protected Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
async protected virtual Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = 0;
@ -91,7 +91,7 @@ namespace FreeSql.Internal.CommonProvider
ClearData();
return ret;
}
async protected Task<List<T1>> SplitExecuteUpdatedAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
async protected virtual Task<List<T1>> SplitExecuteUpdatedAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = new List<T1>();

View File

@ -54,7 +54,7 @@ namespace FreeSql.Internal
public abstract string NowUtc { get; }
public abstract string QuoteWriteParamterAdapter(Type type, string paramterName);
protected abstract string QuoteReadColumnAdapter(Type type, Type mapType, string columnName);
public string RewriteColumn(ColumnInfo col, string sql)
public virtual string RewriteColumn(ColumnInfo col, string sql)
{
if (string.IsNullOrWhiteSpace(col?.Attribute.RewriteSql) == false)
return string.Format(col.Attribute.RewriteSql, sql);

View File

@ -31,6 +31,7 @@ namespace FreeSql.Internal.Model
/// <returns></returns>
public object GetDbValue(object obj)
{
if (Table.IsDictionaryType) return (obj as Dictionary<string, object>)?.TryGetValue(CsName, out var tryval) == true ? tryval : null;
var dbval = Table.GetPropertyValue(obj, CsName);
//if (ConversionCsToDb != null) dbval = ConversionCsToDb(dbval);
if (Attribute.MapType != CsType) dbval = Utils.GetDataReaderValue(Attribute.MapType, dbval);
@ -40,13 +41,27 @@ namespace FreeSql.Internal.Model
/// 获取 obj.CsName 属性原始值(不经过 MapType
/// </summary>
/// <param name="obj"></param>
public object GetValue(object obj) => Table.GetPropertyValue(obj, CsName);
public object GetValue(object obj)
{
if (Table.IsDictionaryType) return (obj as Dictionary<string, object>)?.TryGetValue(CsName, out var tryval) == true ? tryval : null;
return Table.GetPropertyValue(obj, CsName);
}
/// <summary>
/// 设置 obj.CsName 属性值
/// </summary>
/// <param name="obj"></param>
/// <param name="val"></param>
public void SetValue(object obj, object val) => Table.SetPropertyValue(obj, CsName, Utils.GetDataReaderValue(CsType, val));
public void SetValue(object obj, object val)
{
if (Table.IsDictionaryType)
{
var dic = obj as Dictionary<string, object>;
if (dic.ContainsKey(CsName)) dic[CsName] = val;
else dic.Add(CsName, val);
return;
}
Table.SetPropertyValue(obj, CsName, Utils.GetDataReaderValue(CsType, val));
}

View File

@ -120,6 +120,28 @@ namespace FreeSql.Internal.Model
/// not in (1,2,3)<para></para>
/// 此时 Value 的值格式为逗号分割value1,value2,value3... 或者数组
/// </summary>
NotAny
NotAny,
/// <summary>
/// 自定义解析,此时 Field 为反射信息Value 为静态方法的参数(string)<para></para>
/// 示范:{ Operator: "Custom", Field: "RawSql webapp1.DynamicFilterCustom,webapp1", Value: "(id,name) in ((1,'k'),(2,'m'))" }<para></para>
/// 注意:使用者自己承担【注入风险】<para></para>
/// 静态方法定义示范:<para></para>
/// namespace webapp1<para></para>
/// {<para></para>
/// public class DynamicFilterCustom<para></para>
/// {<para></para>
/// [DynamicFilterCustom]<para></para>
/// public static string RawSql(string value) => value;<para></para>
/// }<para></para>
/// }<para></para>
/// </summary>
Custom
}
/// <summary>
/// 授权 DynamicFilter 支持 Custom 自定义解析
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class DynamicFilterCustomAttribute : Attribute { }
}

View File

@ -25,6 +25,7 @@ namespace FreeSql.Internal.Model
public bool DisableSyncStructure { get; set; }
public string Comment { get; internal set; }
public bool IsRereadSql { get; internal set; }
public bool IsDictionaryType { get; internal set; }
public ColumnInfo VersionColumn { get; set; }

View File

@ -17,6 +17,7 @@ namespace FreeSql.Internal.ObjectPool
public bool IsThrowGetTimeoutException { get; set; } = true;
public bool IsAutoDisposeWithSystem { get; set; } = true;
public int CheckAvailableInterval { get; set; } = 5;
public int Weight { get; set; } = 1;
public Func<T> CreateObject;
public Action<Object<T>> OnGetObject;

View File

@ -48,6 +48,11 @@ namespace FreeSql.Internal.ObjectPool
/// </summary>
int CheckAvailableInterval { get; set; }
/// <summary>
/// 权重
/// </summary>
int Weight { get; set; }
/// <summary>
/// 对象池的对象被创建时
/// </summary>

View File

@ -4,6 +4,7 @@ using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
@ -118,7 +119,7 @@ namespace FreeSql.Internal
var leftBt = colattr.DbType.IndexOf('(');
colattr.DbType = colattr.DbType.Substring(0, leftBt).ToUpper() + colattr.DbType.Substring(leftBt);
}
else
else if (common._orm.Ado.DataType != DataType.ClickHouse)
colattr.DbType = colattr.DbType.ToUpper();
if (colattrIsNull == false && colattrIsNullable == true) colattr.DbType = colattr.DbType.Replace("NOT NULL", "");
@ -129,12 +130,13 @@ namespace FreeSql.Internal
if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower();
if (common.CodeFirst.IsSyncStructureToUpper) colattr.Name = colattr.Name.ToUpper();
if ((colattr.IsNullable != true || colattr.IsIdentity == true || colattr.IsPrimary == true) && colattr.DbType.Contains("NOT NULL") == false)
if ((colattr.IsNullable != true || colattr.IsIdentity == true || colattr.IsPrimary == true) && colattr.DbType.Contains("NOT NULL") == false && common._orm.Ado.DataType != DataType.ClickHouse)
{
colattr.IsNullable = false;
colattr.DbType = Regex.Replace(colattr.DbType, @"\bNULL\b", "").Trim() + " NOT NULL";
}
if (colattr.IsNullable == true && colattr.DbType.Contains("NOT NULL")) colattr.DbType = colattr.DbType.Replace("NOT NULL", "");
else if (colattr.IsNullable == true && !colattr.DbType.Contains("Nullable") && common._orm.Ado.DataType == DataType.ClickHouse) colattr.DbType = $"Nullable({colattr.DbType})";
colattr.DbType = Regex.Replace(colattr.DbType, @"\([^\)]+\)", m =>
{
var tmpLt = Regex.Replace(m.Groups[0].Value, @"\s", "");
@ -203,6 +205,36 @@ namespace FreeSql.Internal
// else if (Math.Abs(dt.Subtract(DateTime.UtcNow).TotalSeconds) < 60)
// col.DbDefaultValue = common.NowUtc;
//}
if (common._orm.Ado.DataType == DataType.GBase)
{
if (colattr.IsIdentity == true)
{
var colType = col.CsType.NullableTypeOrThis();
if (colType == typeof(int) || colType == typeof(uint))
colattr.DbType = "SERIAL";
else if (colType == typeof(long) || colType == typeof(ulong))
colattr.DbType = "SERIAL8";
}
if (colattr.MapType.NullableTypeOrThis() == typeof(DateTime))
{
if (colattr._Precision == null)
{
colattr.DbType = "DATETIME YEAR TO FRACTION(3)";
colattr.Precision = 3;
col.DbPrecision = 3;
}
else if (colattr._Precision == 0)
{
colattr.DbType = "DATETIME YEAR TO SECOND";
}
else if (colattr._Precision > 0)
{
colattr.DbType = $"DATETIME YEAR TO FRACTION({colattr.Precision})";
col.DbPrecision = (byte)colattr.Precision;
}
}
}
if (colattr.ServerTime != DateTimeKind.Unspecified && new[] { typeof(DateTime), typeof(DateTimeOffset) }.Contains(colattr.MapType.NullableTypeOrThis()))
{
var commonNow = common.Now;
@ -234,12 +266,13 @@ namespace FreeSql.Internal
{
int strlen = colattr.StringLength;
var charPatten = @"(CHARACTER|CHAR2|CHAR)\s*(\([^\)]*\))?";
var strNotNull = colattr.IsNullable == false ? " NOT NULL" : "";
switch (common._orm.Ado.DataType)
{
case DataType.MySql:
case DataType.OdbcMySql:
if (strlen == -2) colattr.DbType = "LONGTEXT";
else if (strlen < 0) colattr.DbType = "TEXT";
if (strlen == -2) colattr.DbType = $"LONGTEXT{strNotNull}";
else if (strlen < 0) colattr.DbType = $"TEXT{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.SqlServer:
@ -252,15 +285,15 @@ namespace FreeSql.Internal
case DataType.KingbaseES:
case DataType.OdbcKingbaseES:
case DataType.ShenTong:
if (strlen < 0) colattr.DbType = "TEXT";
if (strlen < 0) colattr.DbType = $"TEXT{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.Oracle:
if (strlen < 0) colattr.DbType = "NCLOB"; //v1.3.2+ https://github.com/dotnetcore/FreeSql/issues/259
if (strlen < 0) colattr.DbType = $"NCLOB{strNotNull}"; //v1.3.2+ https://github.com/dotnetcore/FreeSql/issues/259
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.Dameng:
if (strlen < 0) colattr.DbType = "TEXT";
if (strlen < 0) colattr.DbType = $"TEXT{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.OdbcOracle:
@ -269,17 +302,21 @@ namespace FreeSql.Internal
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.Sqlite:
if (strlen < 0) colattr.DbType = "TEXT";
if (strlen < 0) colattr.DbType = $"TEXT{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.MsAccess:
charPatten = @"(CHAR|CHAR2|CHARACTER|TEXT)\s*(\([^\)]*\))?";
if (strlen < 0) colattr.DbType = "LONGTEXT";
if (strlen < 0) colattr.DbType = $"LONGTEXT{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.Firebird:
charPatten = @"(CHAR|CHAR2|CHARACTER|TEXT)\s*(\([^\)]*\))?";
if (strlen < 0) colattr.DbType = "BLOB SUB_TYPE 1";
if (strlen < 0) colattr.DbType = $"BLOB SUB_TYPE 1{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
case DataType.GBase:
if (strlen < 0) colattr.DbType = $"TEXT{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, charPatten, $"$1({strlen})");
break;
}
@ -289,12 +326,13 @@ namespace FreeSql.Internal
{
int strlen = colattr.StringLength;
var bytePatten = @"(VARBINARY|BINARY|BYTEA)\s*(\([^\)]*\))?";
var strNotNull = colattr.IsNullable == false ? " NOT NULL" : "";
switch (common._orm.Ado.DataType)
{
case DataType.MySql:
case DataType.OdbcMySql:
if (strlen == -2) colattr.DbType = "LONGBLOB";
else if (strlen < 0) colattr.DbType = "BLOB";
if (strlen == -2) colattr.DbType = $"LONGBLOB{strNotNull}";
else if (strlen < 0) colattr.DbType = $"BLOB{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, bytePatten, $"$1({strlen})");
break;
case DataType.SqlServer:
@ -307,27 +345,30 @@ namespace FreeSql.Internal
case DataType.KingbaseES:
case DataType.OdbcKingbaseES:
case DataType.ShenTong: //驱动引发的异常:“System.Data.OscarClient.OscarException”(位于 System.Data.OscarClient.dll 中)
colattr.DbType = "BYTEA"; //变长二进制串
colattr.DbType = $"BYTEA{strNotNull}"; //变长二进制串
break;
case DataType.Oracle:
colattr.DbType = "BLOB";
colattr.DbType = $"BLOB{strNotNull}";
break;
case DataType.Dameng:
colattr.DbType = "BLOB";
colattr.DbType = $"BLOB{strNotNull}";
break;
case DataType.OdbcOracle:
case DataType.OdbcDameng:
colattr.DbType = "BLOB";
colattr.DbType = $"BLOB{strNotNull}";
break;
case DataType.Sqlite:
colattr.DbType = "BLOB";
colattr.DbType = $"BLOB{strNotNull}";
break;
case DataType.MsAccess:
if (strlen < 0) colattr.DbType = "BLOB";
if (strlen < 0) colattr.DbType = $"BLOB{strNotNull}";
else colattr.DbType = Regex.Replace(colattr.DbType, bytePatten, $"$1({strlen})");
break;
case DataType.Firebird:
colattr.DbType = "BLOB";
colattr.DbType = $"BLOB{strNotNull}";
break;
case DataType.GBase:
colattr.DbType = $"BYTE{strNotNull}";
break;
}
}
@ -1234,12 +1275,13 @@ namespace FreeSql.Internal
});
public static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter)
where T : IDataParameter
{
if (string.IsNullOrEmpty(sql) || obj == null) return new T[0];
var isCheckSql = sql != "*";
var ttype = typeof(T);
var type = obj.GetType();
if (type == ttype) return new[] { (T)Convert.ChangeType(obj, type) };
if (ttype.IsAssignableFrom(type)) return new[] { (T)obj };
var ret = new List<T>();
var dic = obj as IDictionary;
if (dic != null)
@ -1250,7 +1292,7 @@ namespace FreeSql.Internal
if (isCheckSql && string.IsNullOrEmpty(paramPrefix) == false && sql.IndexOf($"{paramPrefix}{dbkey}", StringComparison.CurrentCultureIgnoreCase) == -1) continue;
var val = dic[key];
var valType = val == null ? typeof(string) : val.GetType();
if (valType == ttype) ret.Add((T)Convert.ChangeType(val, ttype));
if (ttype.IsAssignableFrom(valType)) ret.Add((T)val);
else ret.Add(constructorParamter(dbkey, valType, val));
}
}
@ -1261,7 +1303,7 @@ namespace FreeSql.Internal
{
if (isCheckSql && string.IsNullOrEmpty(paramPrefix) == false && sql.IndexOf($"{paramPrefix}{p.Name}", StringComparison.CurrentCultureIgnoreCase) == -1) continue;
var pvalue = p.GetValue(obj, null);
if (p.PropertyType == ttype) ret.Add((T)Convert.ChangeType(pvalue, ttype));
if (ttype.IsAssignableFrom(p.PropertyType)) ret.Add((T)pvalue);
else ret.Add(constructorParamter(p.Name, p.PropertyType, pvalue));
}
}
@ -1333,7 +1375,7 @@ namespace FreeSql.Internal
this.Value = value;
this.DataIndex = dataIndex;
}
public static ConstructorInfo Constructor = typeof(RowInfo). GetConstructor(new[] { typeof(object), typeof(int) });
public static ConstructorInfo Constructor = typeof(RowInfo).GetConstructor(new[] { typeof(object), typeof(int) });
public static PropertyInfo PropertyValue = typeof(RowInfo).GetProperty("Value");
public static PropertyInfo PropertyDataIndex = typeof(RowInfo).GetProperty("DataIndex");
}
@ -1351,6 +1393,7 @@ namespace FreeSql.Internal
switch (orm.Ado.DataType)
{
case DataType.Dameng: //OdbcDameng 不会报错
case DataType.GBase:
if (dr.IsDBNull(index)) return null;
break;
}
@ -1464,7 +1507,7 @@ namespace FreeSql.Internal
), new[] { typeExp, indexesExp, rowExp, dataIndexExp, commonUtilExp }).Compile();
}
if (type == typeof(object) && indexes != null)
if (type == typeof(object) && indexes != null || type == typeof(Dictionary<string, object>))
{
Func<Type, int[], DbDataReader, int, CommonUtils, RowInfo> dynamicFunc = (type2, indexes2, row2, dataindex2, commonUtils2) =>
{
@ -1812,7 +1855,7 @@ namespace FreeSql.Internal
static MethodInfo MethodBigIntegerParse = typeof(Utils).GetMethod("ToBigInteger", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string) }, null);
static PropertyInfo PropertyDateTimeOffsetDateTime = typeof(DateTimeOffset).GetProperty("DateTime", BindingFlags.Instance | BindingFlags.Public);
static PropertyInfo PropertyDateTimeTicks = typeof(DateTime).GetProperty("Ticks", BindingFlags.Instance | BindingFlags.Public);
static ConstructorInfo CtorDateTimeOffsetArgsTicks = typeof(DateTimeOffset). GetConstructor(new[] { typeof(long), typeof(TimeSpan) });
static ConstructorInfo CtorDateTimeOffsetArgsTicks = typeof(DateTimeOffset).GetConstructor(new[] { typeof(long), typeof(TimeSpan) });
static Encoding DefaultEncoding = Encoding.UTF8;
static MethodInfo MethodEncodingGetBytes = typeof(Encoding).GetMethod("GetBytes", new[] { typeof(string) });
static MethodInfo MethodEncodingGetString = typeof(Encoding).GetMethod("GetString", new[] { typeof(byte[]) });
@ -1831,7 +1874,7 @@ namespace FreeSql.Internal
{
if (type.IsArray)
{
switch (type.FullName)
switch (type.FullName)
{
case "System.Byte[]":
return Expression.IfThenElse(