mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-19 20:38:16 +08:00
pgsql/mysql/sqlserver适配
This commit is contained in:
256
FreeSql/Internal/CommonExpression.cs
Normal file
256
FreeSql/Internal/CommonExpression.cs
Normal file
@ -0,0 +1,256 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal {
|
||||
internal abstract class CommonExpression {
|
||||
|
||||
internal CommonUtils _common;
|
||||
internal CommonExpression(CommonUtils common) {
|
||||
_common = common;
|
||||
}
|
||||
|
||||
internal bool ReadAnonymousField(List<SelectTableInfo> _tables, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp) {
|
||||
switch (exp.NodeType) {
|
||||
case ExpressionType.Quote: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand);
|
||||
case ExpressionType.Lambda: return ReadAnonymousField(_tables, field, parent, ref index, (exp as LambdaExpression)?.Body);
|
||||
case ExpressionType.Convert: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand);
|
||||
case ExpressionType.Constant:
|
||||
var constExp = exp as ConstantExpression;
|
||||
field.Append(", ").Append(constExp?.Value).Append(" as").Append(++index);
|
||||
return false;
|
||||
case ExpressionType.MemberAccess:
|
||||
var map = new List<SelectColumnInfo>();
|
||||
ExpressionSelectColumn_MemberAccess(_tables, map, SelectTableInfoType.From, exp, true);
|
||||
if (map.Count > 1) {
|
||||
parent.Consturctor = map.First().Table.Table.Type.GetConstructor(new Type[0]);
|
||||
parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
|
||||
}
|
||||
for (var idx = 0; idx < map.Count; idx++) {
|
||||
field.Append(", ").Append(map[idx].Table.Alias).Append(".").Append(_common.QuoteSqlName(map[idx].Column.Attribute.Name)).Append(" as").Append(++index);
|
||||
if (map.Count > 1) parent.Childs.Add(new ReadAnonymousTypeInfo { CsName = map[idx].Column.CsName });
|
||||
}
|
||||
return false;
|
||||
case ExpressionType.New:
|
||||
var newExp = exp as NewExpression;
|
||||
parent.Consturctor = newExp.Type.GetConstructors()[0];
|
||||
parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Arguments;
|
||||
for (var a = 0; a < newExp.Members.Count; a++) {
|
||||
var child = new ReadAnonymousTypeInfo { CsName = newExp.Members[a].Name };
|
||||
parent.Childs.Add(child);
|
||||
ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
internal object ReadAnonymous(ReadAnonymousTypeInfo parent, object[] dr, ref int index) {
|
||||
if (parent.Childs.Any() == false) return dr[++index];
|
||||
switch (parent.ConsturctorType) {
|
||||
case ReadAnonymousTypeInfoConsturctorType.Arguments:
|
||||
var args = new object[parent.Childs.Count];
|
||||
for (var a = 0; a < parent.Childs.Count; a++) {
|
||||
args[a] = ReadAnonymous(parent.Childs[a], dr, ref index);
|
||||
}
|
||||
return parent.Consturctor.Invoke(args);
|
||||
case ReadAnonymousTypeInfoConsturctorType.Properties:
|
||||
var ret = parent.Consturctor.Invoke(null);
|
||||
for (var b = 0; b < parent.Childs.Count; b++) {
|
||||
Utils.FillPropertyValue(ret, parent.Childs[b].CsName, ReadAnonymous(parent.Childs[b], dr, ref index));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal string ExpressionConstant(ConstantExpression exp) => _common.FormatSql("{0}", exp?.Value);
|
||||
|
||||
internal string ExpressionSelectColumn_MemberAccess(List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, Expression exp, bool isQuoteName) {
|
||||
return ExpressionLambdaToSql(exp, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
}
|
||||
|
||||
internal string[] ExpressionSelectColumns_MemberAccess_New_NewArrayInit(List<SelectTableInfo> _tables, Expression exp, bool isQuoteName) {
|
||||
switch (exp?.NodeType) {
|
||||
case ExpressionType.Quote: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName);
|
||||
case ExpressionType.Lambda: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as LambdaExpression)?.Body, isQuoteName);
|
||||
case ExpressionType.Convert: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName);
|
||||
case ExpressionType.Constant: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName) };
|
||||
case ExpressionType.MemberAccess: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName) };
|
||||
case ExpressionType.New:
|
||||
var newExp = exp as NewExpression;
|
||||
if (newExp == null) break;
|
||||
var newExpMembers = new string[newExp.Members.Count];
|
||||
for (var a = 0; a < newExpMembers.Length; a++) newExpMembers[a] = ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, newExp.Arguments[a], isQuoteName);
|
||||
return newExpMembers;
|
||||
case ExpressionType.NewArrayInit:
|
||||
var newArr = exp as NewArrayExpression;
|
||||
if (newArr == null) break;
|
||||
var newArrMembers = new List<string>();
|
||||
foreach (var newArrExp in newArr.Expressions) newArrMembers.AddRange(ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, newArrExp, isQuoteName));
|
||||
return newArrMembers.ToArray();
|
||||
}
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
static readonly Dictionary<ExpressionType, string> dicExpressionOperator = new Dictionary<ExpressionType, string>() {
|
||||
{ ExpressionType.OrElse, "OR" },
|
||||
{ ExpressionType.Or, "|" },
|
||||
{ ExpressionType.AndAlso, "AND" },
|
||||
{ ExpressionType.And, "&" },
|
||||
{ ExpressionType.GreaterThan, ">" },
|
||||
{ ExpressionType.GreaterThanOrEqual, ">=" },
|
||||
{ ExpressionType.LessThan, "<" },
|
||||
{ ExpressionType.LessThanOrEqual, "<=" },
|
||||
{ ExpressionType.NotEqual, "<>" },
|
||||
{ ExpressionType.Add, "+" },
|
||||
{ ExpressionType.Subtract, "-" },
|
||||
{ ExpressionType.Multiply, "*" },
|
||||
{ ExpressionType.Divide, "/" },
|
||||
{ ExpressionType.Modulo, "%" },
|
||||
{ ExpressionType.Equal, "=" },
|
||||
};
|
||||
internal string ExpressionWhereLambdaNoneForeignObject(List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Expression exp) {
|
||||
return ExpressionLambdaToSql(exp, _tables, _selectColumnMap, SelectTableInfoType.From, true);
|
||||
}
|
||||
|
||||
internal string ExpressionWhereLambda(List<SelectTableInfo> _tables, Expression exp) {
|
||||
return ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true);
|
||||
}
|
||||
internal void ExpressionJoinLambda(List<SelectTableInfo> _tables, SelectTableInfoType tbtype, Expression exp) {
|
||||
var tbidx = _tables.Count;
|
||||
var filter = ExpressionLambdaToSql(exp, _tables, null, tbtype, true);
|
||||
if (_tables.Count > tbidx) {
|
||||
_tables[tbidx].Type = tbtype;
|
||||
_tables[tbidx].On = filter;
|
||||
for (var a = tbidx + 1; a < _tables.Count; a++)
|
||||
_tables[a].Type = SelectTableInfoType.From;
|
||||
} else {
|
||||
var find = _tables.Where((a, c) => c > 0 && a.Type == tbtype && string.IsNullOrEmpty(a.On)).LastOrDefault();
|
||||
if (find != null) find.On = filter;
|
||||
}
|
||||
}
|
||||
|
||||
internal string ExpressionLambdaToSql(Expression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) {
|
||||
switch( exp.NodeType) {
|
||||
case ExpressionType.Quote: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
case ExpressionType.Lambda: return ExpressionLambdaToSql((exp as LambdaExpression)?.Body, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
case ExpressionType.Convert: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
case ExpressionType.Constant: return _common.FormatSql("{0}", (exp as ConstantExpression)?.Value);
|
||||
case ExpressionType.MemberAccess:
|
||||
var expStack = new Stack<Expression>();
|
||||
expStack.Push(exp);
|
||||
MethodCallExpression callExp = null;
|
||||
var exp2 = (exp as MemberExpression).Expression;
|
||||
while (true) {
|
||||
switch(exp2.NodeType) {
|
||||
case ExpressionType.Constant:
|
||||
expStack.Push(exp2);
|
||||
break;
|
||||
case ExpressionType.Parameter:
|
||||
expStack.Push(exp2);
|
||||
break;
|
||||
case ExpressionType.MemberAccess:
|
||||
expStack.Push(exp2);
|
||||
exp2 = (exp2 as MemberExpression).Expression;
|
||||
if (exp2 == null) break;
|
||||
continue;
|
||||
case ExpressionType.Call:
|
||||
callExp = exp2 as MethodCallExpression;
|
||||
expStack.Push(exp2);
|
||||
exp2 = callExp.Object;
|
||||
if (exp2 == null) break;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (expStack.First().NodeType != ExpressionType.Parameter) return _common.FormatSql("{0}", Expression.Lambda(exp).Compile().DynamicInvoke());
|
||||
if (callExp != null) return ExpressionLambdaToSqlCall(callExp, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
if (_tables == null) {
|
||||
var pp = expStack.Pop() as ParameterExpression;
|
||||
var memberExp = expStack.Pop() as MemberExpression;
|
||||
var tb = _common.GetTableByEntity(pp.Type);
|
||||
if (tb.ColumnsByCs.ContainsKey(memberExp.Member.Name) == false) throw new ArgumentException($"{tb.DbName} 找不到列 {memberExp.Member.Name}");
|
||||
if (_selectColumnMap != null) {
|
||||
_selectColumnMap.Add(new SelectColumnInfo { Table = null, Column = tb.ColumnsByCs[memberExp.Member.Name] });
|
||||
}
|
||||
var name = tb.ColumnsByCs[memberExp.Member.Name].Attribute.Name;
|
||||
if (isQuoteName) name = _common.QuoteSqlName(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
TableInfo tb2 = null;
|
||||
string alias2 = "", name2 = "";
|
||||
SelectTableInfo find2 = null;
|
||||
while (expStack.Count > 0) {
|
||||
exp2 = expStack.Pop();
|
||||
switch (exp2.NodeType) {
|
||||
case ExpressionType.Constant:
|
||||
throw new NotImplementedException("未现实 MemberAccess 下的 Constant");
|
||||
case ExpressionType.Parameter:
|
||||
case ExpressionType.MemberAccess:
|
||||
var tb2tmp = _common.GetTableByEntity(exp2.Type);
|
||||
var mp2 = exp2 as MemberExpression;
|
||||
if (tb2tmp != null) {
|
||||
if (exp2.NodeType == ExpressionType.Parameter) alias2 = (exp2 as ParameterExpression).Name;
|
||||
else alias2 = $"{alias2}__{mp2.Member.Name}";
|
||||
var find2s = _tables.Where((a2, c2) => a2.Table.CsName == tb2tmp.CsName).ToArray();
|
||||
if (find2s.Length > 1) find2s = _tables.Where((a2, c2) => a2.Table.CsName == tb2tmp.CsName && a2.Alias == alias2).ToArray();
|
||||
find2 = find2s.FirstOrDefault();
|
||||
if (find2 == null) _tables.Add(find2 = new SelectTableInfo { Table = tb2tmp, Alias = alias2, On = null, Type = tbtype });
|
||||
alias2 = find2.Alias;
|
||||
tb2 = tb2tmp;
|
||||
}
|
||||
if (mp2 == null || expStack.Any()) continue;
|
||||
if (tb2.ColumnsByCs.ContainsKey(mp2.Member.Name) == false) { //如果选的是对象,附加所有列
|
||||
if (_selectColumnMap != null) {
|
||||
var tb3 = _common.GetTableByEntity(mp2.Type);
|
||||
if (tb3 != null) {
|
||||
var alias3 = $"{alias2}__{mp2.Member.Name}";
|
||||
var find3s = _tables.Where((a3, c3) => a3.Table.CsName == tb3.CsName).ToArray();
|
||||
if (find3s.Length > 1) find3s = _tables.Where((a3, c3) => a3.Table.CsName == tb3.CsName && a3.Alias == alias3).ToArray();
|
||||
var find3 = find3s.FirstOrDefault();
|
||||
if (find3 == null) _tables.Add(find3 = new SelectTableInfo { Table = tb3, Alias = alias3, On = null, Type = tbtype });
|
||||
alias3 = find3.Alias;
|
||||
|
||||
foreach (var tb3c in tb3.Columns.Values)
|
||||
_selectColumnMap.Add(new SelectColumnInfo { Table = find3, Column = tb3c });
|
||||
if (tb3.Columns.Any()) return "";
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"{tb2.DbName} 找不到列 {mp2.Member.Name}");
|
||||
}
|
||||
var col2 = tb2.ColumnsByCs[mp2.Member.Name];
|
||||
if (_selectColumnMap != null && find2 != null) {
|
||||
_selectColumnMap.Add(new SelectColumnInfo { Table = find2, Column = col2 });
|
||||
return "";
|
||||
}
|
||||
name2 = tb2.ColumnsByCs[mp2.Member.Name].Attribute.Name;
|
||||
break;
|
||||
case ExpressionType.Call:break;
|
||||
}
|
||||
}
|
||||
if (isQuoteName) name2 = _common.QuoteSqlName(name2);
|
||||
return $"{alias2}.{name2}";
|
||||
case ExpressionType.Call: return ExpressionLambdaToSqlCall(exp as MethodCallExpression, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
}
|
||||
if (dicExpressionOperator.TryGetValue(exp.NodeType, out var tryoper) == false) return "";
|
||||
var expBinary = exp as BinaryExpression;
|
||||
if (expBinary == null) return "";
|
||||
var left = ExpressionLambdaToSql(expBinary.Left, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
var right = ExpressionLambdaToSql(expBinary.Right, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||
if (left == "NULL") {
|
||||
var tmp = right;
|
||||
right = left;
|
||||
left = tmp;
|
||||
}
|
||||
if (right == "NULL") tryoper = tryoper == "=" ? " IS " : " IS NOT ";
|
||||
return $"{left} {tryoper} {right}";
|
||||
}
|
||||
|
||||
internal abstract string ExpressionLambdaToSqlCall(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName);
|
||||
|
||||
}
|
||||
}
|
267
FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs
Normal file
267
FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs
Normal file
@ -0,0 +1,267 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SafeObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
abstract partial class AdoProvider : IAdo {
|
||||
|
||||
protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex);
|
||||
protected abstract DbCommand CreateCommand();
|
||||
protected abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
|
||||
|
||||
public bool IsTracePerformance { get; set; } = string.Compare(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), "Development", true) == 0;
|
||||
|
||||
public ObjectPool<DbConnection> MasterPool { get; protected set; }
|
||||
public List<ObjectPool<DbConnection>> SlavePools { get; } = new List<ObjectPool<DbConnection>>();
|
||||
protected ICache _cache { get; set; }
|
||||
protected ILogger _log { get; set; }
|
||||
protected int slaveUnavailables = 0;
|
||||
private object slaveLock = new object();
|
||||
private Random slaveRandom = new Random();
|
||||
|
||||
public AdoProvider(ICache cache, ILogger log) {
|
||||
this._cache = cache;
|
||||
this._log = log;
|
||||
}
|
||||
|
||||
void LoggerException(ObjectPool<DbConnection> pool, DbCommand cmd, Exception e, DateTime dt, string logtxt, bool isThrowException = true) {
|
||||
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}");
|
||||
}
|
||||
|
||||
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 ?? "NULL") + "\r\n";
|
||||
|
||||
log += e.Message;
|
||||
_log.LogError(log);
|
||||
|
||||
RollbackTransaction();
|
||||
cmd.Parameters.Clear();
|
||||
if (isThrowException) throw e;
|
||||
}
|
||||
|
||||
public List<T> Query<T>(string sql, object parms = null) => Query<T>(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
public List<T> Query<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||
var ds = new List<object[]>();
|
||||
ExecuteReader(dr => {
|
||||
if (names.Any() == false)
|
||||
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
||||
object[] values = new object[dr.FieldCount];
|
||||
dr.GetValues(values);
|
||||
ds.Add(values);
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
var ret = new List<T>();
|
||||
foreach (var row in ds) {
|
||||
var read = Utils.ExecuteArrayRowReadClassOrTuple(typeof(T), names, row);
|
||||
ret.Add(read.value == null ? default(T) : (T) read.value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
public void ExecuteReader(Action<DbDataReader> readerHander, string sql, object parms = null) => ExecuteReader(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
public void ExecuteReader(Action<DbDataReader> readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
DateTime dt = DateTime.Now;
|
||||
string logtxt = "";
|
||||
DateTime logtxt_dt = DateTime.Now;
|
||||
var pool = this.MasterPool;
|
||||
bool isSlave = false;
|
||||
|
||||
//读写分离规则
|
||||
if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) {
|
||||
var availables = slaveUnavailables == 0 ?
|
||||
//查从库
|
||||
this.SlavePools : (
|
||||
//查主库
|
||||
slaveUnavailables == this.SlavePools.Count ? new List<ObjectPool<DbConnection>>() :
|
||||
//查从库可用
|
||||
this.SlavePools.Where(sp => sp.IsAvailable).ToList());
|
||||
if (availables.Any()) {
|
||||
isSlave = true;
|
||||
pool = availables.Count == 1 ? availables[0] : availables[slaveRandom.Next(availables.Count)];
|
||||
}
|
||||
}
|
||||
|
||||
Object<DbConnection> conn = null;
|
||||
var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt);
|
||||
if (IsTracePerformance) logtxt += $"PrepareCommand: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
Exception ex = null;
|
||||
try {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
if (isSlave) {
|
||||
//从库查询切换,恢复
|
||||
bool isSlaveFail = false;
|
||||
try {
|
||||
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = pool.Get()).Value;
|
||||
//if (slaveRandom.Next(100) % 2 == 0) throw new Exception("测试从库抛出异常");
|
||||
} catch {
|
||||
isSlaveFail = true;
|
||||
}
|
||||
if (isSlaveFail) {
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(pool, pc.cmd, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false);
|
||||
pc.cmd.Parameters.Clear();
|
||||
ExecuteReader(readerHander, cmdType, cmdText, cmdParms);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
//主库查询
|
||||
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = pool.Get()).Value;
|
||||
}
|
||||
if (IsTracePerformance) {
|
||||
logtxt += $"Open: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
logtxt_dt = DateTime.Now;
|
||||
}
|
||||
using (var dr = pc.cmd.ExecuteReader()) {
|
||||
if (IsTracePerformance) logtxt += $"ExecuteReader: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
while (true) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
bool isread = dr.Read();
|
||||
if (IsTracePerformance) logtxt += $" dr.Read: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
if (isread == false) break;
|
||||
|
||||
if (readerHander != null) {
|
||||
object[] values = null;
|
||||
if (IsTracePerformance) {
|
||||
logtxt_dt = DateTime.Now;
|
||||
values = new object[dr.FieldCount];
|
||||
dr.GetValues(values);
|
||||
logtxt += $" dr.GetValues: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
logtxt_dt = DateTime.Now;
|
||||
}
|
||||
readerHander(dr);
|
||||
if (IsTracePerformance) logtxt += $" readerHander: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms ({string.Join(",", values)})\r\n";
|
||||
}
|
||||
}
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
dr.Close();
|
||||
}
|
||||
if (IsTracePerformance) logtxt += $"ExecuteReader_dispose: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
} catch (Exception ex2) {
|
||||
ex = ex2;
|
||||
}
|
||||
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(pool, pc.cmd, ex, dt, logtxt);
|
||||
pc.cmd.Parameters.Clear();
|
||||
}
|
||||
public object[][] ExecuteArray(string sql, object parms = null) => ExecuteArray(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
public object[][] ExecuteArray(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
List<object[]> ret = new List<object[]>();
|
||||
ExecuteReader(dr => {
|
||||
object[] values = new object[dr.FieldCount];
|
||||
dr.GetValues(values);
|
||||
ret.Add(values);
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
return ret.ToArray();
|
||||
}
|
||||
public DataTable ExecuteDataTable(string sql, object parms = null) => ExecuteDataTable(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
public DataTable ExecuteDataTable(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
var ret = new DataTable();
|
||||
ExecuteReader(dr => {
|
||||
if (ret.Columns.Count == 0)
|
||||
for (var a = 0; a < dr.FieldCount; a++) ret.Columns.Add(dr.GetName(a));
|
||||
object[] values = new object[ret.Columns.Count];
|
||||
dr.GetValues(values);
|
||||
ret.Rows.Add(values);
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
return ret;
|
||||
}
|
||||
public int ExecuteNonQuery(string sql, object parms = null) => ExecuteNonQuery(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
public int ExecuteNonQuery(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
DateTime dt = DateTime.Now;
|
||||
string logtxt = "";
|
||||
DateTime logtxt_dt = DateTime.Now;
|
||||
Object<DbConnection> conn = null;
|
||||
var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt);
|
||||
int val = 0;
|
||||
Exception ex = null;
|
||||
try {
|
||||
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = this.MasterPool.Get()).Value;
|
||||
val = pc.cmd.ExecuteNonQuery();
|
||||
} catch (Exception ex2) {
|
||||
ex = ex2;
|
||||
}
|
||||
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(this.MasterPool, pc.cmd, ex, dt, logtxt);
|
||||
pc.cmd.Parameters.Clear();
|
||||
return val;
|
||||
}
|
||||
public object ExecuteScalar(string sql, object parms = null) => ExecuteScalar(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
public object ExecuteScalar(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
DateTime dt = DateTime.Now;
|
||||
string logtxt = "";
|
||||
DateTime logtxt_dt = DateTime.Now;
|
||||
Object<DbConnection> conn = null;
|
||||
var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt);
|
||||
object val = null;
|
||||
Exception ex = null;
|
||||
try {
|
||||
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = this.MasterPool.Get()).Value;
|
||||
val = pc.cmd.ExecuteScalar();
|
||||
} catch (Exception ex2) {
|
||||
ex = ex2;
|
||||
}
|
||||
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(this.MasterPool, pc.cmd, ex, dt, logtxt);
|
||||
pc.cmd.Parameters.Clear();
|
||||
return val;
|
||||
}
|
||||
|
||||
private (DbTransaction tran, DbCommand cmd) PrepareCommand(CommandType cmdType, string cmdText, DbParameter[] cmdParms, ref string logtxt) {
|
||||
var dt = DateTime.Now;
|
||||
DbCommand cmd = CreateCommand();
|
||||
cmd.CommandType = cmdType;
|
||||
cmd.CommandText = cmdText;
|
||||
|
||||
if (cmdParms != null) {
|
||||
foreach (var parm in cmdParms) {
|
||||
if (parm == null) continue;
|
||||
if (parm.Value == null) parm.Value = DBNull.Value;
|
||||
cmd.Parameters.Add(parm);
|
||||
}
|
||||
}
|
||||
|
||||
var tran = TransactionCurrentThread;
|
||||
if (IsTracePerformance) logtxt += $" PrepareCommand_part1: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmdParms.Length}\r\n";
|
||||
|
||||
if (tran != null) {
|
||||
if (IsTracePerformance) dt = DateTime.Now;
|
||||
cmd.Connection = tran.Connection;
|
||||
cmd.Transaction = tran;
|
||||
if (IsTracePerformance) logtxt += $" PrepareCommand_tran!=null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
}
|
||||
|
||||
if (IsTracePerformance) dt = DateTime.Now;
|
||||
AutoCommitTransaction();
|
||||
if (IsTracePerformance) logtxt += $" AutoCommitTransaction: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
|
||||
return (tran, cmd);
|
||||
}
|
||||
}
|
||||
}
|
215
FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs
Normal file
215
FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs
Normal file
@ -0,0 +1,215 @@
|
||||
using SafeObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
partial class AdoProvider {
|
||||
public Task<List<T>> QueryAsync<T>(string sql, object parms = null) => QueryAsync<T>(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
async public Task<List<T>> QueryAsync<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||
var ds = new List<object[]>();
|
||||
await ExecuteReaderAsync(async dr => {
|
||||
if (names.Any() == false)
|
||||
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
||||
object[] values = new object[dr.FieldCount];
|
||||
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||
ds.Add(values);
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
var ret = new List<T>();
|
||||
foreach (var row in ds) {
|
||||
var read = Utils.ExecuteArrayRowReadClassOrTuple(typeof(T), names, row);
|
||||
ret.Add(read.value == null ? default(T) : (T) read.value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
public Task ExecuteReaderAsync(Func<DbDataReader, Task> readerHander, string sql, object parms = null) => ExecuteReaderAsync(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
async public Task ExecuteReaderAsync(Func<DbDataReader, Task> readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
DateTime dt = DateTime.Now;
|
||||
string logtxt = "";
|
||||
DateTime logtxt_dt = DateTime.Now;
|
||||
var pool = this.MasterPool;
|
||||
bool isSlave = false;
|
||||
|
||||
//读写分离规则
|
||||
if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) {
|
||||
var availables = slaveUnavailables == 0 ?
|
||||
//查从库
|
||||
this.SlavePools : (
|
||||
//查主库
|
||||
slaveUnavailables == this.SlavePools.Count ? new List<ObjectPool<DbConnection>>() :
|
||||
//查从库可用
|
||||
this.SlavePools.Where(sp => sp.IsAvailable).ToList());
|
||||
if (availables.Any()) {
|
||||
isSlave = true;
|
||||
pool = availables.Count == 1 ? this.SlavePools[0] : availables[slaveRandom.Next(availables.Count)];
|
||||
}
|
||||
}
|
||||
|
||||
Object<DbConnection> conn = null;
|
||||
var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt);
|
||||
if (IsTracePerformance) logtxt += $"PrepareCommand: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
Exception ex = null;
|
||||
try {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
if (isSlave) {
|
||||
//从库查询切换,恢复
|
||||
bool isSlaveFail = false;
|
||||
try {
|
||||
if (cmd.Connection == null) cmd.Connection = (conn = await pool.GetAsync()).Value;
|
||||
//if (slaveRandom.Next(100) % 2 == 0) throw new Exception("测试从库抛出异常");
|
||||
} catch {
|
||||
isSlaveFail = true;
|
||||
}
|
||||
if (isSlaveFail) {
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(pool, cmd, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false);
|
||||
cmd.Parameters.Clear();
|
||||
await ExecuteReaderAsync(readerHander, cmdType, cmdText, cmdParms);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
//主库查询
|
||||
if (cmd.Connection == null) cmd.Connection = (conn = await pool.GetAsync()).Value;
|
||||
}
|
||||
if (IsTracePerformance) {
|
||||
logtxt += $"Open: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
logtxt_dt = DateTime.Now;
|
||||
}
|
||||
using (var dr = await cmd.ExecuteReaderAsync()) {
|
||||
if (IsTracePerformance) logtxt += $"ExecuteReader: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
while (true) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
bool isread = await dr.ReadAsync();
|
||||
if (IsTracePerformance) logtxt += $" dr.Read: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
if (isread == false) break;
|
||||
|
||||
if (readerHander != null) {
|
||||
object[] values = null;
|
||||
if (IsTracePerformance) {
|
||||
logtxt_dt = DateTime.Now;
|
||||
values = new object[dr.FieldCount];
|
||||
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||
logtxt += $" dr.GetValues: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
logtxt_dt = DateTime.Now;
|
||||
}
|
||||
await readerHander(dr);
|
||||
if (IsTracePerformance) logtxt += $" readerHander: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms ({string.Join(",", values)})\r\n";
|
||||
}
|
||||
}
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
dr.Close();
|
||||
}
|
||||
if (IsTracePerformance) logtxt += $"ExecuteReader_dispose: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
} catch (Exception ex2) {
|
||||
ex = ex2;
|
||||
}
|
||||
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(pool, cmd, ex, dt, logtxt);
|
||||
cmd.Parameters.Clear();
|
||||
}
|
||||
public Task ExecuteArrayAsync(string sql, object parms = null) => ExecuteArrayAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
async public Task<object[][]> ExecuteArrayAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
List<object[]> ret = new List<object[]>();
|
||||
await ExecuteReaderAsync(async dr => {
|
||||
object[] values = new object[dr.FieldCount];
|
||||
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||
ret.Add(values);
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
return ret.ToArray();
|
||||
}
|
||||
public Task<DataTable> ExecuteDataTableAsync(string sql, object parms = null) => ExecuteDataTableAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
async public Task<DataTable> ExecuteDataTableAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
var ret = new DataTable();
|
||||
await ExecuteReaderAsync(async dr => {
|
||||
if (ret.Columns.Count == 0)
|
||||
for (var a = 0; a < dr.FieldCount; a++) ret.Columns.Add(dr.GetName(a));
|
||||
object[] values = new object[ret.Columns.Count];
|
||||
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||
ret.Rows.Add(values);
|
||||
}, cmdType, cmdText, cmdParms);
|
||||
return ret;
|
||||
}
|
||||
public Task<int> ExecuteNonQueryAsync(string sql, object parms = null) => ExecuteNonQueryAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
async public Task<int> ExecuteNonQueryAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
DateTime dt = DateTime.Now;
|
||||
string logtxt = "";
|
||||
Object<DbConnection> conn = null;
|
||||
var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt);
|
||||
var logtxt_dt = DateTime.Now;
|
||||
int val = 0;
|
||||
Exception ex = null;
|
||||
try {
|
||||
if (cmd.Connection == null) cmd.Connection = (conn = await this.MasterPool.GetAsync()).Value;
|
||||
val = await cmd.ExecuteNonQueryAsync();
|
||||
} catch (Exception ex2) {
|
||||
ex = ex2;
|
||||
}
|
||||
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(this.MasterPool, cmd, ex, dt, logtxt);
|
||||
cmd.Parameters.Clear();
|
||||
return val;
|
||||
}
|
||||
public Task<object> ExecuteScalarAsync(string sql, object parms = null) => ExecuteScalarAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||
async public Task<object> ExecuteScalarAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||
var dt = DateTime.Now;
|
||||
var logtxt = "";
|
||||
Object<DbConnection> conn = null;
|
||||
var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt);
|
||||
var logtxt_dt = DateTime.Now;
|
||||
object val = null;
|
||||
Exception ex = null;
|
||||
try {
|
||||
if (cmd.Connection == null) cmd.Connection = (conn = await this.MasterPool.GetAsync()).Value;
|
||||
val = await cmd.ExecuteScalarAsync();
|
||||
} catch (Exception ex2) {
|
||||
ex = ex2;
|
||||
}
|
||||
|
||||
if (conn != null) {
|
||||
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||
}
|
||||
LoggerException(this.MasterPool, cmd, ex, dt, logtxt);
|
||||
cmd.Parameters.Clear();
|
||||
return val;
|
||||
}
|
||||
|
||||
private DbCommand PrepareCommandAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, ref string logtxt) {
|
||||
DateTime dt = DateTime.Now;
|
||||
DbCommand cmd = CreateCommand();
|
||||
cmd.CommandType = cmdType;
|
||||
cmd.CommandText = cmdText;
|
||||
|
||||
if (cmdParms != null) {
|
||||
foreach (var parm in cmdParms) {
|
||||
if (parm == null) continue;
|
||||
if (parm.Value == null) parm.Value = DBNull.Value;
|
||||
cmd.Parameters.Add(parm);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsTracePerformance) logtxt += $" PrepareCommand_tran==null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using SafeObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
partial class AdoProvider {
|
||||
|
||||
class Transaction2 {
|
||||
internal Object<DbConnection> Conn;
|
||||
internal DbTransaction Transaction;
|
||||
internal DateTime RunTime;
|
||||
internal TimeSpan Timeout;
|
||||
|
||||
public Transaction2(Object<DbConnection> conn, DbTransaction tran, TimeSpan timeout) {
|
||||
Conn = conn;
|
||||
Transaction = tran;
|
||||
RunTime = DateTime.Now;
|
||||
Timeout = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<int, Transaction2> _trans = new Dictionary<int, Transaction2>();
|
||||
private object _trans_lock = new object();
|
||||
|
||||
public DbTransaction TransactionCurrentThread => _trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var conn) && conn.Transaction?.Connection != null ? conn.Transaction : null;
|
||||
|
||||
private Dictionary<int, List<string>> _preRemoveKeys = new Dictionary<int, List<string>>();
|
||||
private object _preRemoveKeys_lock = new object();
|
||||
public string[] PreRemove(params string[] key) {
|
||||
var tid = Thread.CurrentThread.ManagedThreadId;
|
||||
List<string> keys = null;
|
||||
if (key == null || key.Any() == false) return _preRemoveKeys.TryGetValue(tid, out keys) ? keys.ToArray() : new string[0];
|
||||
_log.LogDebug($"线程{tid}事务预删除 {JsonConvert.SerializeObject(key)}");
|
||||
if (_preRemoveKeys.TryGetValue(tid, out keys) == false)
|
||||
lock (_preRemoveKeys_lock)
|
||||
if (_preRemoveKeys.TryGetValue(tid, out keys) == false) {
|
||||
_preRemoveKeys.Add(tid, keys = new List<string>(key));
|
||||
return key;
|
||||
}
|
||||
keys.AddRange(key);
|
||||
return keys.ToArray();
|
||||
}
|
||||
public void TransactionPreRemoveCache(params string[] key) => PreRemove(key);
|
||||
|
||||
/// <summary>
|
||||
/// 启动事务
|
||||
/// </summary>
|
||||
public void BeginTransaction(TimeSpan timeout) {
|
||||
int tid = Thread.CurrentThread.ManagedThreadId;
|
||||
Transaction2 tran = null;
|
||||
Object<DbConnection> conn = null;
|
||||
|
||||
try {
|
||||
conn = MasterPool.Get();
|
||||
tran = new Transaction2(conn, conn.Value.BeginTransaction(), timeout);
|
||||
} catch(Exception ex) {
|
||||
_log.LogError($"数据库出错(开启事务){ex.Message} \r\n{ex.StackTrace}");
|
||||
throw ex;
|
||||
}
|
||||
if (_trans.ContainsKey(tid)) CommitTransaction();
|
||||
|
||||
lock (_trans_lock)
|
||||
_trans.Add(tid, tran);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动提交事务
|
||||
/// </summary>
|
||||
private void AutoCommitTransaction() {
|
||||
if (_trans.Count > 0) {
|
||||
Transaction2[] trans = null;
|
||||
lock (_trans_lock)
|
||||
trans = _trans.Values.Where(st2 => DateTime.Now.Subtract(st2.RunTime) > st2.Timeout).ToArray();
|
||||
foreach (Transaction2 tran in trans) CommitTransaction(true, tran);
|
||||
}
|
||||
}
|
||||
private void CommitTransaction(bool isCommit, Transaction2 tran) {
|
||||
if (tran == null || tran.Transaction == null || tran.Transaction.Connection == null) return;
|
||||
|
||||
if (_trans.ContainsKey(tran.Conn.LastGetThreadId))
|
||||
lock (_trans_lock)
|
||||
if (_trans.ContainsKey(tran.Conn.LastGetThreadId))
|
||||
_trans.Remove(tran.Conn.LastGetThreadId);
|
||||
|
||||
var removeKeys = PreRemove();
|
||||
if (_preRemoveKeys.ContainsKey(tran.Conn.LastGetThreadId))
|
||||
lock (_preRemoveKeys_lock)
|
||||
if (_preRemoveKeys.ContainsKey(tran.Conn.LastGetThreadId))
|
||||
_preRemoveKeys.Remove(tran.Conn.LastGetThreadId);
|
||||
|
||||
Exception ex = null;
|
||||
var f001 = isCommit ? "提交" : "回滚";
|
||||
try {
|
||||
_log.LogDebug($"线程{tran.Conn.LastGetThreadId}事务{f001},批量删除缓存key {Newtonsoft.Json.JsonConvert.SerializeObject(removeKeys)}");
|
||||
_cache.Remove(removeKeys);
|
||||
if (isCommit) tran.Transaction.Commit();
|
||||
else tran.Transaction.Rollback();
|
||||
} catch (Exception ex2) {
|
||||
ex = ex2;
|
||||
_log.LogError($"数据库出错({f001}事务):{ex.Message} {ex.StackTrace}");
|
||||
} finally {
|
||||
ReturnConnection(MasterPool, tran.Conn, ex); //MasterPool.Return(tran.Conn, ex);
|
||||
}
|
||||
}
|
||||
private void CommitTransaction(bool isCommit) {
|
||||
if (_trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var tran)) CommitTransaction(isCommit, tran);
|
||||
}
|
||||
/// <summary>
|
||||
/// 提交事务
|
||||
/// </summary>
|
||||
public void CommitTransaction() => CommitTransaction(true);
|
||||
/// <summary>
|
||||
/// 回滚事务
|
||||
/// </summary>
|
||||
public void RollbackTransaction() => CommitTransaction(false);
|
||||
|
||||
public void Dispose() {
|
||||
Transaction2[] trans = null;
|
||||
lock (_trans_lock)
|
||||
trans = _trans.Values.ToArray();
|
||||
foreach (Transaction2 tran in trans) CommitTransaction(false, tran);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启事务(不支持异步),60秒未执行完将自动提交
|
||||
/// </summary>
|
||||
/// <param name="handler">事务体 () => {}</param>
|
||||
public void Transaction(Action handler) {
|
||||
Transaction(handler, TimeSpan.FromSeconds(60));
|
||||
}
|
||||
/// <summary>
|
||||
/// 开启事务(不支持异步)
|
||||
/// </summary>
|
||||
/// <param name="handler">事务体 () => {}</param>
|
||||
/// <param name="timeout">超时,未执行完将自动提交</param>
|
||||
public void Transaction(Action handler, TimeSpan timeout) {
|
||||
try {
|
||||
BeginTransaction(timeout);
|
||||
handler();
|
||||
CommitTransaction();
|
||||
} catch (Exception ex) {
|
||||
RollbackTransaction();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
partial class AdoProvider {
|
||||
|
||||
public abstract object AddslashesProcessParam(object param);
|
||||
public string Addslashes(string filter, params object[] parms) {
|
||||
if (filter == null || parms == null) return string.Empty;
|
||||
if (parms.Length == 0) return filter;
|
||||
var nparms = new object[parms.Length];
|
||||
for (int a = 0; a < parms.Length; a++) {
|
||||
if (parms[a] == null)
|
||||
filter = Regex.Replace(filter, @"\s*(=|IN)\s*\{" + a + @"\}", " IS {" + a + "}", RegexOptions.IgnoreCase);
|
||||
nparms[a] = AddslashesProcessParam(parms[a]);
|
||||
}
|
||||
try { string ret = string.Format(filter, nparms); return ret; } catch { return filter; }
|
||||
}
|
||||
}
|
||||
}
|
176
FreeSql/Internal/CommonProvider/CacheProvider.cs
Normal file
176
FreeSql/Internal/CommonProvider/CacheProvider.cs
Normal file
@ -0,0 +1,176 @@
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
class CacheProvider : ICache {
|
||||
|
||||
public IDistributedCache Cache { get; private set; }
|
||||
private bool CacheSupportMultiRemove = false;
|
||||
private static DateTime dt1970 = new DateTime(1970, 1, 1);
|
||||
|
||||
public CacheProvider(IDistributedCache cache, ILogger log) {
|
||||
if (cache == null) cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions { }));
|
||||
Cache = cache;
|
||||
var key1 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
|
||||
var key2 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
|
||||
Cache.Set(key1, new byte[] { 65 });
|
||||
Cache.Set(key2, new byte[] { 65 });
|
||||
try { Cache.Remove($"{key1}|{key2}"); } catch { } // redis-cluster 不允许执行 multi keys 命令
|
||||
CacheSupportMultiRemove = Cache.Get(key1) == null && cache.Get(key2) == null;
|
||||
if (CacheSupportMultiRemove == false) {
|
||||
log.LogWarning("FreeSql Warning: 低性能, IDistributedCache 没现实批量删除缓存 Cache.Remove(\"key1|key2\").");
|
||||
Remove(key1, key2);
|
||||
}
|
||||
}
|
||||
|
||||
public Func<object, string> Serialize { get; set; }
|
||||
public Func<string, Type, object> Deserialize { get; set; }
|
||||
|
||||
Func<JsonSerializerSettings> JsonSerializerSettings = () => {
|
||||
var st = new JsonSerializerSettings();
|
||||
st.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
|
||||
st.DateFormatHandling = DateFormatHandling.IsoDateFormat;
|
||||
st.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
|
||||
return st;
|
||||
};
|
||||
string SerializeObject(object value) {
|
||||
if (Serialize != null) return Serialize(value);
|
||||
return JsonConvert.SerializeObject(value, this.JsonSerializerSettings());
|
||||
}
|
||||
T DeserializeObject<T>(string value) {
|
||||
if (Deserialize != null) return (T) Deserialize(value, typeof(T));
|
||||
return JsonConvert.DeserializeObject<T>(value, this.JsonSerializerSettings());
|
||||
}
|
||||
|
||||
public void Set<T>(string key, T data, int timeoutSeconds = 0) {
|
||||
if (string.IsNullOrEmpty(key)) return;
|
||||
Cache.Set(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||
}
|
||||
public T Get<T>(string key) {
|
||||
if (string.IsNullOrEmpty(key)) return default(T);
|
||||
var value = Cache.Get(key);
|
||||
if (value == null) return default(T);
|
||||
return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
|
||||
}
|
||||
public string Get(string key) {
|
||||
if (string.IsNullOrEmpty(key)) return null;
|
||||
var value = Cache.Get(key);
|
||||
if (value == null) return null;
|
||||
return Encoding.UTF8.GetString(value);
|
||||
}
|
||||
|
||||
async public Task SetAsync<T>(string key, T data, int timeoutSeconds = 0) {
|
||||
if (string.IsNullOrEmpty(key)) return;
|
||||
await Cache.SetAsync(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||
}
|
||||
async public Task<T> GetAsync<T>(string key) {
|
||||
if (string.IsNullOrEmpty(key)) return default(T);
|
||||
var value = await Cache.GetAsync(key);
|
||||
if (value == null) return default(T);
|
||||
return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
|
||||
}
|
||||
async public Task<string> GetAsync(string key) {
|
||||
if (string.IsNullOrEmpty(key)) return null;
|
||||
var value = await Cache.GetAsync(key);
|
||||
if (value == null) return null;
|
||||
return Encoding.UTF8.GetString(value);
|
||||
}
|
||||
|
||||
public void Remove(params string[] keys) {
|
||||
if (keys == null || keys.Length == 0) return;
|
||||
var keysDistinct = keys.Distinct();
|
||||
if (CacheSupportMultiRemove) Cache.Remove(string.Join("|", keysDistinct));
|
||||
else foreach (var key in keysDistinct) Cache.Remove(key);
|
||||
}
|
||||
|
||||
async public Task RemoveAsync(params string[] keys) {
|
||||
if (keys == null || keys.Length == 0) return;
|
||||
var keysDistinct = keys.Distinct();
|
||||
if (CacheSupportMultiRemove) await Cache.RemoveAsync(string.Join("|", keysDistinct));
|
||||
else foreach (var key in keysDistinct) await Cache.RemoveAsync(key);
|
||||
}
|
||||
|
||||
public T Shell<T>(string key, int timeoutSeconds, Func<T> getData) {
|
||||
if (timeoutSeconds <= 0) return getData();
|
||||
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||
var cacheValue = Cache.Get(key);
|
||||
if (cacheValue != null) {
|
||||
try {
|
||||
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||
return DeserializeObject<T>(txt);
|
||||
} catch {
|
||||
Cache.Remove(key);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
var ret = getData();
|
||||
Cache.Set(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||
return ret;
|
||||
}
|
||||
|
||||
public T Shell<T>(string key, string field, int timeoutSeconds, Func<T> getData) {
|
||||
if (timeoutSeconds <= 0) return getData();
|
||||
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||
var hashkey = $"{key}:{field}";
|
||||
var cacheValue = Cache.Get(hashkey);
|
||||
if (cacheValue != null) {
|
||||
try {
|
||||
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||
var value = DeserializeObject<(T, long)>(txt);
|
||||
if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
|
||||
} catch {
|
||||
Cache.Remove(hashkey);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
var ret = (getData(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
|
||||
Cache.Set(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
|
||||
return ret.Item1;
|
||||
}
|
||||
|
||||
async public Task<T> ShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getDataAsync) {
|
||||
if (timeoutSeconds <= 0) return await getDataAsync();
|
||||
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||
var cacheValue = await Cache.GetAsync(key);
|
||||
if (cacheValue != null) {
|
||||
try {
|
||||
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||
return DeserializeObject<T>(txt);
|
||||
} catch {
|
||||
await Cache.RemoveAsync(key);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
var ret = await getDataAsync();
|
||||
await Cache.SetAsync(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||
return ret;
|
||||
}
|
||||
|
||||
async public Task<T> ShellAsync<T>(string key, string field, int timeoutSeconds, Func<Task<T>> getDataAsync) {
|
||||
if (timeoutSeconds <= 0) return await getDataAsync();
|
||||
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||
var hashkey = $"{key}:{field}";
|
||||
var cacheValue = await Cache.GetAsync(hashkey);
|
||||
if (cacheValue != null) {
|
||||
try {
|
||||
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||
var value = DeserializeObject<(T, long)>(txt);
|
||||
if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
|
||||
} catch {
|
||||
await Cache.RemoveAsync(hashkey);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
var ret = (await getDataAsync(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
|
||||
await Cache.SetAsync(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
|
||||
return ret.Item1;
|
||||
}
|
||||
}
|
||||
}
|
52
FreeSql/Internal/CommonProvider/DeleteProvider.cs
Normal file
52
FreeSql/Internal/CommonProvider/DeleteProvider.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract partial class DeleteProvider<T1> : IDelete<T1> where T1 : class {
|
||||
protected IFreeSql _orm;
|
||||
protected CommonUtils _commonUtils;
|
||||
protected CommonExpression _commonExpression;
|
||||
protected List<T1> _source = new List<T1>();
|
||||
protected TableInfo _table;
|
||||
protected StringBuilder _where = new StringBuilder();
|
||||
protected int _whereTimes = 0;
|
||||
protected List<DbParameter> _params = new List<DbParameter>();
|
||||
|
||||
public DeleteProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) {
|
||||
_orm = orm;
|
||||
_commonUtils = commonUtils;
|
||||
_commonExpression = commonExpression;
|
||||
_table = _commonUtils.GetTableByEntity(typeof(T1));
|
||||
_where.Append("DELETE FROM ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append(" WHERE ");
|
||||
this.Where(_commonUtils.WhereObject(_table, "", dywhere));
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||
}
|
||||
|
||||
public long ExecuteAffrows() {
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
return _orm.Ado.ExecuteNonQuery(CommandType.Text, sql, _params.ToArray());
|
||||
}
|
||||
public abstract List<T1> ExecuteDeleted();
|
||||
|
||||
public IDelete<T1> Where(Expression<Func<T1, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, exp?.Body));
|
||||
public IDelete<T1> Where(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(sql)) return this;
|
||||
if (++_whereTimes > 1) _where.Append(" AND ");
|
||||
_where.Append("(").Append(sql).Append(")");
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this;
|
||||
}
|
||||
public IDelete<T1> Where(T1 item) => this.Where(new[] { item });
|
||||
public IDelete<T1> Where(IEnumerable<T1> items) => this.Where(_commonUtils.WhereItems(_table, "", items));
|
||||
public IDelete<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class => this.Where($"{(notExists ? "NOT " : "")}EXISTS({select.ToSql("1")})");
|
||||
|
||||
public string ToSql() => _whereTimes <= 0 ? null : _where.ToString();
|
||||
}
|
||||
}
|
90
FreeSql/Internal/CommonProvider/InsertProvider.cs
Normal file
90
FreeSql/Internal/CommonProvider/InsertProvider.cs
Normal file
@ -0,0 +1,90 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract partial class InsertProvider<T1> : IInsert<T1> where T1 : class {
|
||||
protected IFreeSql _orm;
|
||||
protected CommonUtils _commonUtils;
|
||||
protected CommonExpression _commonExpression;
|
||||
protected List<T1> _source = new List<T1>();
|
||||
protected Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||
protected TableInfo _table;
|
||||
protected DbParameter[] _params;
|
||||
|
||||
public InsertProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) {
|
||||
_orm = orm;
|
||||
_commonUtils = commonUtils;
|
||||
_commonExpression = commonExpression;
|
||||
_table = _commonUtils.GetTableByEntity(typeof(T1));
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||
}
|
||||
|
||||
public IInsert<T1> AppendData(T1 source) {
|
||||
if (source != null) _source.Add(source);
|
||||
return this;
|
||||
}
|
||||
public IInsert<T1> AppendData(IEnumerable<T1> source) {
|
||||
if (source != null) _source.AddRange(source.Where(a => a != null));
|
||||
return this;
|
||||
}
|
||||
|
||||
public long ExecuteAffrows() => _orm.Ado.ExecuteNonQuery(CommandType.Text, this.ToSql(), _params);
|
||||
public abstract long ExecuteIdentity();
|
||||
public abstract List<T1> ExecuteInserted();
|
||||
|
||||
public IInsert<T1> IgnoreColumns(Expression<Func<T1, object>> columns) {
|
||||
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).Distinct();
|
||||
_ignore.Clear();
|
||||
foreach (var col in cols) _ignore.Add(col, true);
|
||||
return this;
|
||||
}
|
||||
public IInsert<T1> InsertColumns(Expression<Func<T1, object>> columns) {
|
||||
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).ToDictionary(a => a, a => true);
|
||||
_ignore.Clear();
|
||||
foreach (var col in _table.Columns.Values)
|
||||
if (cols.ContainsKey(col.Attribute.Name) == false)
|
||||
_ignore.Add(col.Attribute.Name, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public string ToSql() {
|
||||
if (_source == null || _source.Any() == false) return null;
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append("(");
|
||||
var colidx = 0;
|
||||
foreach (var col in _table.Columns.Values)
|
||||
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name) == false) {
|
||||
if (colidx > 0) sb.Append(", ");
|
||||
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
|
||||
++colidx;
|
||||
}
|
||||
if (colidx == 0) return null;
|
||||
sb.Append(") VALUES");
|
||||
_params = new DbParameter[colidx * _source.Count];
|
||||
var didx = 0;
|
||||
foreach (var d in _source) {
|
||||
if (didx > 0) sb.Append(", ");
|
||||
sb.Append("(");
|
||||
var colidx2 = 0;
|
||||
foreach (var col in _table.Columns.Values)
|
||||
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name) == false) {
|
||||
if (colidx2 > 0) sb.Append(", ");
|
||||
sb.Append("?").Append(col.CsName).Append(didx);
|
||||
_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value);
|
||||
++colidx2;
|
||||
}
|
||||
sb.Append(")");
|
||||
++didx;
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,263 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select0Provider<TSelect, T1> : ISelect0<TSelect, T1> where TSelect : class where T1 : class {
|
||||
|
||||
protected int _limit, _skip;
|
||||
protected string _select = "SELECT ", _orderby, _groupby, _having;
|
||||
protected StringBuilder _where = new StringBuilder();
|
||||
protected List<DbParameter> _params = new List<DbParameter>();
|
||||
protected List<SelectTableInfo> _tables = new List<SelectTableInfo>();
|
||||
protected StringBuilder _join = new StringBuilder();
|
||||
protected (int seconds, string key) _cache = (0, null);
|
||||
protected IFreeSql _orm;
|
||||
protected CommonUtils _commonUtils;
|
||||
protected CommonExpression _commonExpression;
|
||||
|
||||
internal static void CopyData(Select0Provider<TSelect, T1> from, object to) {
|
||||
var toType = to?.GetType();
|
||||
if (toType == null) return;
|
||||
toType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._limit);
|
||||
toType.GetField("_skip", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._skip);
|
||||
toType.GetField("_select", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._select);
|
||||
toType.GetField("_where", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._where.ToString()));
|
||||
toType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<DbParameter>(from._params.ToArray()));
|
||||
toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<SelectTableInfo>(from._tables.ToArray()));
|
||||
toType.GetField("_join", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._join.ToString()));
|
||||
toType.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._cache);
|
||||
//toType.GetField("_orm", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._orm);
|
||||
//toType.GetField("_commonUtils", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonUtils);
|
||||
//toType.GetField("_commonExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonExpression);
|
||||
}
|
||||
|
||||
public Select0Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) {
|
||||
_orm = orm;
|
||||
_commonUtils = commonUtils;
|
||||
_commonExpression = commonExpression;
|
||||
_tables.Add(new SelectTableInfo { Table = _commonUtils.GetTableByEntity(typeof(T1)), Alias = "a", On = null, Type = SelectTableInfoType.From });
|
||||
this.Where(_commonUtils.WhereObject(_tables.First().Table, "a.", dywhere));
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||
}
|
||||
|
||||
public bool Any() {
|
||||
this.Limit(1);
|
||||
return this.ToList<int>("1").FirstOrDefault() == 1;
|
||||
}
|
||||
public TSelect Caching(int seconds, string key = null) {
|
||||
_cache = (seconds, key);
|
||||
return this as TSelect;
|
||||
}
|
||||
public long Count() => this.ToList<int>("count(1)").FirstOrDefault();
|
||||
public TSelect Count(out long count) {
|
||||
count = this.Count();
|
||||
return this as TSelect;
|
||||
}
|
||||
|
||||
public TSelect GroupBy(string sql, object parms = null) {
|
||||
_groupby = sql;
|
||||
if (string.IsNullOrEmpty(_groupby)) return this as TSelect;
|
||||
_groupby = string.Concat(" \r\nGROUP BY ", _groupby);
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(_groupby, parms));
|
||||
return this as TSelect;
|
||||
}
|
||||
public TSelect Having(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(_groupby) || string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||
_having = string.Concat(_having, " AND (", sql, ")");
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this as TSelect;
|
||||
}
|
||||
|
||||
public TSelect LeftJoin(Expression<Func<T1, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.LeftJoin);
|
||||
public TSelect InnerJoin(Expression<Func<T1, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.InnerJoin);
|
||||
public TSelect RightJoin(Expression<Func<T1, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.RightJoin);
|
||||
public TSelect LeftJoin<T2>(Expression<Func<T1, T2, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.LeftJoin);
|
||||
public TSelect InnerJoin<T2>(Expression<Func<T1, T2, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.InnerJoin);
|
||||
public TSelect RightJoin<T2>(Expression<Func<T1, T2, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.RightJoin);
|
||||
|
||||
public TSelect InnerJoin(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||
_join.Append(" \r\nINNER JOIN ").Append(sql);
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this as TSelect;
|
||||
}
|
||||
public TSelect LeftJoin(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||
_join.Append(" \r\nLEFT JOIN ").Append(sql);
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this as TSelect;
|
||||
}
|
||||
|
||||
public TSelect Limit(int limit) {
|
||||
_limit = limit;
|
||||
return this as TSelect;
|
||||
}
|
||||
public TSelect Master() {
|
||||
_select = " SELECT ";
|
||||
return this as TSelect;
|
||||
}
|
||||
public TSelect Offset(int offset) => this.Skip(offset) as TSelect;
|
||||
|
||||
public TSelect OrderBy(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(sql)) _orderby = null;
|
||||
_orderby = string.Concat(string.IsNullOrEmpty(_orderby) ? " \r\nORDER BY " : "", _orderby, sql);
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this as TSelect;
|
||||
}
|
||||
public TSelect Page(int pageIndex, int pageSize) {
|
||||
this.Skip(Math.Max(0, pageIndex - 1) * pageSize);
|
||||
return this.Limit(pageSize) as TSelect;
|
||||
}
|
||||
|
||||
public TSelect RightJoin(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||
_join.Append(" \r\nRIGHT JOIN ").Append(sql);
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this as TSelect;
|
||||
}
|
||||
|
||||
public TSelect Skip(int offset) {
|
||||
_skip = offset;
|
||||
return this as TSelect;
|
||||
}
|
||||
public TSelect Take(int limit) => this.Limit(limit) as TSelect;
|
||||
|
||||
public List<TTuple> ToList<TTuple>(string field) {
|
||||
var sql = this.ToSql(field);
|
||||
if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = sql;
|
||||
|
||||
return _orm.Cache.Shell(_cache.key, _cache.seconds, () => {
|
||||
List<TTuple> ret = new List<TTuple>();
|
||||
Type type = typeof(TTuple);
|
||||
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql, _params.ToArray());
|
||||
foreach (var dr in ds) {
|
||||
var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr);
|
||||
ret.Add(read.value == null ? default(TTuple) : (TTuple)read.value);
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
public List<T1> ToList() {
|
||||
return this.ToList<T1>(this.GetAllField());
|
||||
}
|
||||
public T1 ToOne() {
|
||||
this.Limit(1);
|
||||
return ToList().FirstOrDefault();
|
||||
}
|
||||
|
||||
protected List<TReturn> ToList<TReturn>((ReadAnonymousTypeInfo map, string field) af) {
|
||||
var sql = this.ToSql(af.field);
|
||||
if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
|
||||
|
||||
var drarr = _orm.Cache.Shell(_cache.key, _cache.seconds, () => _orm.Ado.ExecuteArray(CommandType.Text, sql, _params.ToArray()));
|
||||
var ret = new List<TReturn>();
|
||||
for (var a = 0; a < drarr.Length; a++) {
|
||||
var dr = drarr[a];
|
||||
var index = -1;
|
||||
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
protected (ReadAnonymousTypeInfo map, string field) GetNewExpressionField(NewExpression newexp) {
|
||||
var map = new ReadAnonymousTypeInfo();
|
||||
var field = new StringBuilder();
|
||||
var index = 0;
|
||||
|
||||
_commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp);
|
||||
return (map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null);
|
||||
}
|
||||
protected (ReadAnonymousTypeInfo map, string field) GetAllField() {
|
||||
var type = typeof(T1);
|
||||
var map = new ReadAnonymousTypeInfo { Consturctor = type.GetConstructor(new Type[0]), ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties };
|
||||
var field = new StringBuilder();
|
||||
var tb = _tables.First();
|
||||
var index = 0;
|
||||
var ps = typeof(T1).GetProperties();
|
||||
foreach (var p in ps) {
|
||||
var child = new ReadAnonymousTypeInfo { CsName = p.Name };
|
||||
if (tb.Table.ColumnsByCs.TryGetValue(p.Name, out var col)) { //普通字段
|
||||
if (index > 0) field.Append(", ");
|
||||
field.Append(tb.Alias).Append(".").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as").Append(++index);
|
||||
} else {
|
||||
var tb2 = _tables.Where(a => a.Table.Type == p.PropertyType && a.Alias.Contains(p.Name)).FirstOrDefault();
|
||||
if (tb2 == null && ps.Where(pw => pw.PropertyType == p.PropertyType).Count() == 1) tb2 = _tables.Where(a => a.Table.Type == p.PropertyType).FirstOrDefault();
|
||||
if (tb2 == null) continue;
|
||||
child.Consturctor = tb2.Table.Type.GetConstructor(new Type[0]);
|
||||
child.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
|
||||
foreach (var col2 in tb2.Table.Columns.Values) {
|
||||
if (index > 0) field.Append(", ");
|
||||
field.Append(tb2.Alias).Append(".").Append(_commonUtils.QuoteSqlName(col2.Attribute.Name)).Append(" as").Append(++index);
|
||||
child.Childs.Add(new ReadAnonymousTypeInfo { CsName = col2.CsName });
|
||||
}
|
||||
}
|
||||
map.Childs.Add(child);
|
||||
}
|
||||
return (map, field.ToString());
|
||||
}
|
||||
public abstract string ToSql(string field = null);
|
||||
|
||||
public TSelect Where(string sql, object parms = null) => this.WhereIf(true, sql, parms);
|
||||
public TSelect WhereIf(bool condition, string sql, object parms = null) {
|
||||
if (condition == false || string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||
_where.Append(" AND (").Append(sql).Append(")");
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this as TSelect;
|
||||
}
|
||||
#region common
|
||||
|
||||
protected TMember InternalAvg<TMember>(Expression exp) => this.ToList<TMember>($"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||
protected TMember InternalMax<TMember>(Expression exp) => this.ToList<TMember>($"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||
protected TMember InternalMin<TMember>(Expression exp) => this.ToList<TMember>($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||
protected TMember InternalSum<TMember>(Expression exp) => this.ToList<TMember>($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||
|
||||
protected TSelect InternalGroupBy(Expression columns) => this.GroupBy(string.Join(", ", _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, columns, true)));
|
||||
protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType) {
|
||||
_commonExpression.ExpressionJoinLambda(_tables, joinType, exp);
|
||||
return this as TSelect;
|
||||
}
|
||||
protected TSelect InternalJoin<T2>(Expression exp, SelectTableInfoType joinType) {
|
||||
var tb = _commonUtils.GetTableByEntity(typeof(T2));
|
||||
if (tb == null) throw new ArgumentException("T2 类型错误");
|
||||
_tables.Add(new SelectTableInfo { Table = tb, Alias = $"IJ{_tables.Count}", On = null, Type = joinType });
|
||||
_commonExpression.ExpressionJoinLambda(_tables, joinType, exp);
|
||||
return this as TSelect;
|
||||
}
|
||||
protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true));
|
||||
protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true)} DESC");
|
||||
|
||||
protected List<TReturn> InternalToList<TReturn>(Expression select) => this.ToList<TReturn>(this.GetNewExpressionField(select as NewExpression));
|
||||
|
||||
protected TSelect InternalWhere(Expression exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp));
|
||||
protected TSelect InternalWhereLikeOr(Expression columns, string pattern, bool notLike) {
|
||||
if (string.IsNullOrEmpty(pattern)) return this as TSelect;
|
||||
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, columns, true);
|
||||
if (cols.Any() == false) return this as TSelect;
|
||||
var filter = "";
|
||||
foreach (var col in cols) {
|
||||
if (string.IsNullOrEmpty(col)) continue;
|
||||
filter += string.Concat(" OR ", _commonUtils.FormatSql($"{col} {(notLike ? "NOT LIKE" : "LIKE")} {{0}}", pattern));
|
||||
}
|
||||
if (string.IsNullOrEmpty(filter)) return this as TSelect;
|
||||
return this.Where(filter.Substring(4));
|
||||
}
|
||||
protected TSelect InternalWhereLike(Expression column, string pattern, bool notLike) {
|
||||
if (string.IsNullOrEmpty(pattern)) return this as TSelect;
|
||||
string col = _commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true);
|
||||
if (string.IsNullOrEmpty(col)) return this as TSelect;
|
||||
return this.Where(_commonUtils.FormatSql($"{col} {(notLike ? "NOT LIKE" : "LIKE")} {{0}}", pattern));
|
||||
}
|
||||
|
||||
protected TSelect InternalJoin(Expression exp) {
|
||||
return this as TSelect;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class
|
||||
where T10 : class {
|
||||
|
||||
public Select10Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select1Provider<T1> : Select0Provider<ISelect<T1>, T1>, ISelect<T1>
|
||||
where T1 : class {
|
||||
public Select1Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
|
||||
}
|
||||
|
||||
protected ISelect<T1> InternalFrom(Expression exp) {
|
||||
if (exp.NodeType == ExpressionType.Call) {
|
||||
var expCall = exp as MethodCallExpression;
|
||||
var stockCall = new Stack<MethodCallExpression>();
|
||||
while (expCall != null) {
|
||||
stockCall.Push(expCall);
|
||||
expCall = expCall.Object as MethodCallExpression;
|
||||
}
|
||||
while (stockCall.Any()) {
|
||||
expCall = stockCall.Pop();
|
||||
|
||||
switch (expCall.Method.Name) {
|
||||
case "Where": this.InternalWhere(expCall.Arguments[0]); break;
|
||||
case "WhereIf":
|
||||
if (_commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[0], false) == "1")
|
||||
this.InternalWhere(expCall.Arguments[1]);
|
||||
break;
|
||||
case "WhereLike":
|
||||
var whereLikeArg0 = (expCall.Arguments[0] as UnaryExpression).Operand as LambdaExpression;
|
||||
var whereLikeArg1 = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[1], false);
|
||||
var whereLikeArg2 = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[2], false) == "1";
|
||||
if (whereLikeArg0.ReturnType == typeof(string)) this.InternalWhereLike(whereLikeArg0, whereLikeArg1, whereLikeArg2);
|
||||
else this.InternalWhereLikeOr(whereLikeArg0, whereLikeArg1, whereLikeArg2);
|
||||
break;
|
||||
case "GroupBy": this.InternalGroupBy(expCall.Arguments[0]); break;
|
||||
case "OrderBy": this.InternalOrderBy(expCall.Arguments[0]); break;
|
||||
case "OrderByDescending": this.InternalOrderByDescending(expCall.Arguments[0]); break;
|
||||
|
||||
case "LeftJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.LeftJoin); break;
|
||||
case "InnerJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.InnerJoin); break;
|
||||
case "RightJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.RightJoin); break;
|
||||
|
||||
default: throw new NotImplementedException($"未现实 {expCall.Method.Name}");
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
throw new NotImplementedException($"未现实 {exp}");
|
||||
}
|
||||
|
||||
public ISelect<T1> As(string alias) {
|
||||
var oldAs = _tables.First().Alias;
|
||||
var newAs = string.IsNullOrEmpty(alias) ? "a" : alias;
|
||||
if (oldAs != newAs) {
|
||||
_tables.First().Alias = newAs;
|
||||
var wh = _where.ToString();
|
||||
_where.Replace($" {oldAs}.", $" {newAs}.");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public TMember Avg<TMember>(Expression<Func<T1, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;// { this.InternalFrom(exp?.Body); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;// { this.InternalFrom(exp?.Body); var ret = new Select4Provider<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;// { this.InternalFrom(exp?.Body); var ret = new Select5Provider<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;// { this.InternalFrom(exp?.Body); var ret = new Select6Provider<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;// { this.InternalFrom(exp?.Body); var ret = new Select7Provider<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;// { this.InternalFrom(exp?.Body); var ret = new Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;// { this.InternalFrom(exp?.Body); var ret = new Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;// { this.InternalFrom(exp?.Body); var ret = new Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||
|
||||
public ISelect<T1> GroupBy(Expression<Func<T1, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
public TMember Max<TMember>(Expression<Func<T1, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
public TMember Min<TMember>(Expression<Func<T1, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
public ISelect<T1> OrderBy<TMember>(Expression<Func<T1, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
public ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
public TMember Sum<TMember>(Expression<Func<T1, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
public List<TReturn> ToList<TReturn>(Expression<Func<T1, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
public ISelect<T1> Where(Expression<Func<T1, bool>> exp) => this.InternalWhere(exp?.Body);
|
||||
|
||||
public ISelect<T1> Where<T2>(Expression<Func<T1, T2, bool>> exp) where T2 : class => this.InternalWhere(exp?.Body);
|
||||
|
||||
public ISelect<T1> Where<T2, T3>(Expression<Func<T1, T2, T3, bool>> exp) where T2 : class where T3 : class => this.InternalWhere(exp?.Body);
|
||||
|
||||
public ISelect<T1> Where<T2, T3, T4>(Expression<Func<T1, T2, T3, T4, bool>> exp) where T2 : class where T3 : class where T4 : class => this.InternalWhere(exp?.Body);
|
||||
|
||||
public ISelect<T1> Where<T2, T3, T4, T5>(Expression<Func<T1, T2, T3, T4, T5, bool>> exp) where T2 : class where T3 : class where T4 : class where T5 : class => this.InternalWhere(exp?.Body);
|
||||
|
||||
public ISelect<T1> WhereIf(bool condition, Expression<Func<T1, bool>> exp) => condition ? this.InternalWhere(exp?.Body) : this;
|
||||
|
||||
public ISelect<T1> WhereLike(Expression<Func<T1, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
public ISelect<T1> WhereLike(Expression<Func<T1, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select2Provider<T1, T2> : Select0Provider<ISelect<T1, T2>, T1>, ISelect<T1, T2>
|
||||
where T1 : class
|
||||
where T2 : class {
|
||||
|
||||
public Select2Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T2>();
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2>.Avg<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2> ISelect<T1, T2>.GroupBy(Expression<Func<T1, T2, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2>.Max<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2>.Min<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2> ISelect<T1, T2>.OrderBy<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2> ISelect<T1, T2>.OrderByDescending<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2>.Sum<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2>.ToList<TReturn>(Expression<Func<T1, T2, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2> ISelect<T1, T2>.Where(Expression<Func<T1, T2, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2> ISelect<T1, T2>.WhereIf(bool condition, Expression<Func<T1, T2, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2> ISelect<T1, T2>.WhereLike(Expression<Func<T1, T2, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2> ISelect<T1, T2>.WhereLike(Expression<Func<T1, T2, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select3Provider<T1, T2, T3> : Select0Provider<ISelect<T1, T2, T3>, T1>, ISelect<T1, T2, T3>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class {
|
||||
|
||||
public Select3Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3>.Avg<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.GroupBy(Expression<Func<T1, T2, T3, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3>.Max<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3>.Min<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.OrderBy<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3>.Sum<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3>.ToList<TReturn>(Expression<Func<T1, T2, T3, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.Where(Expression<Func<T1, T2, T3, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.WhereIf(bool condition, Expression<Func<T1, T2, T3, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.WhereLike(Expression<Func<T1, T2, T3, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.WhereLike(Expression<Func<T1, T2, T3, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select4Provider<T1, T2, T3, T4> : Select0Provider<ISelect<T1, T2, T3, T4>, T1>, ISelect<T1, T2, T3, T4>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class {
|
||||
|
||||
public Select4Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.GroupBy(Expression<Func<T1, T2, T3, T4, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4>.Max<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4>.Min<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3, T4>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.Where(Expression<Func<T1, T2, T3, T4, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.WhereLike(Expression<Func<T1, T2, T3, T4, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.WhereLike(Expression<Func<T1, T2, T3, T4, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select5Provider<T1, T2, T3, T4, T5> : Select0Provider<ISelect<T1, T2, T3, T4, T5>, T1>, ISelect<T1, T2, T3, T4, T5>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class {
|
||||
|
||||
public Select5Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3, T4, T5>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.Where(Expression<Func<T1, T2, T3, T4, T5, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select6Provider<T1, T2, T3, T4, T5, T6> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6>, T1>, ISelect<T1, T2, T3, T4, T5, T6>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class {
|
||||
|
||||
public Select6Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select7Provider<T1, T2, T3, T4, T5, T6, T7> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class {
|
||||
|
||||
public Select7Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract partial class Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class {
|
||||
|
||||
public Select8Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract class Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>
|
||||
where T1 : class
|
||||
where T2 : class
|
||||
where T3 : class
|
||||
where T4 : class
|
||||
where T5 : class
|
||||
where T6 : class
|
||||
where T7 : class
|
||||
where T8 : class
|
||||
where T9 : class {
|
||||
|
||||
public Select9Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9));
|
||||
}
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||
|
||||
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||
|
||||
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||
|
||||
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||
}
|
||||
}
|
172
FreeSql/Internal/CommonProvider/UpdateProvider.cs
Normal file
172
FreeSql/Internal/CommonProvider/UpdateProvider.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal.CommonProvider {
|
||||
|
||||
abstract partial class UpdateProvider<T1> : IUpdate<T1> where T1 : class {
|
||||
protected IFreeSql _orm;
|
||||
protected CommonUtils _commonUtils;
|
||||
protected CommonExpression _commonExpression;
|
||||
protected List<T1> _source = new List<T1>();
|
||||
protected Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||
protected TableInfo _table;
|
||||
protected StringBuilder _where = new StringBuilder();
|
||||
protected StringBuilder _set = new StringBuilder();
|
||||
protected List<DbParameter> _params = new List<DbParameter>();
|
||||
protected List<DbParameter> _paramsSource = new List<DbParameter>();
|
||||
|
||||
public UpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) {
|
||||
_orm = orm;
|
||||
_commonUtils = commonUtils;
|
||||
_commonExpression = commonExpression;
|
||||
_table = _commonUtils.GetTableByEntity(typeof(T1));
|
||||
this.Where(_commonUtils.WhereObject(_table, "", dywhere));
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||
}
|
||||
|
||||
public long ExecuteAffrows() {
|
||||
var sql = this.ToSql();
|
||||
if (string.IsNullOrEmpty(sql)) return 0;
|
||||
return _orm.Ado.ExecuteNonQuery(CommandType.Text, sql, _params.Concat(_paramsSource).ToArray());
|
||||
}
|
||||
public abstract List<T1> ExecuteUpdated();
|
||||
|
||||
public IUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns) {
|
||||
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).Distinct();
|
||||
_ignore.Clear();
|
||||
foreach (var col in cols) _ignore.Add(col, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IUpdate<T1> SetSource(T1 source) => this.SetSource(new[] { source });
|
||||
public IUpdate<T1> SetSource(IEnumerable<T1> source) {
|
||||
if (source == null || source.Any() == false) return this;
|
||||
_source.AddRange(source.Where(a => a != null));
|
||||
return this.Where(_source);
|
||||
}
|
||||
|
||||
public IUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value) {
|
||||
var col = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, column?.Body, true);
|
||||
if (string.IsNullOrEmpty(col)) return this;
|
||||
_set.Append(", ").Append(col).Append(" = ?p_").Append(_params.Count);
|
||||
_commonUtils.AppendParamter(_params, null, value);
|
||||
//foreach (var t in _source) Utils.FillPropertyValue(t, tryf.CsName, value);
|
||||
return this;
|
||||
}
|
||||
public IUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> binaryExpression) {
|
||||
if (binaryExpression?.Body is BinaryExpression == false) return this;
|
||||
var cols = new List<SelectColumnInfo>();
|
||||
var expt = _commonExpression.ExpressionWhereLambdaNoneForeignObject(null, cols, binaryExpression);
|
||||
if (cols.Any() == false) return this;
|
||||
foreach (var col in cols) {
|
||||
if (col.Column.Attribute.IsNullable) {
|
||||
var repltype = col.Column.CsType;
|
||||
if (repltype.FullName.StartsWith("System.Nullable`1[[System.")) repltype = repltype.GenericTypeArguments[0];
|
||||
var replval = Activator.CreateInstance(repltype);
|
||||
if (replval == null) continue;
|
||||
var replname = _commonUtils.QuoteSqlName(col.Column.Attribute.Name);
|
||||
replval = _commonUtils.FormatSql("{0}", replval);
|
||||
expt = expt.Replace(replname, _commonUtils.IsNull(replname, replval));
|
||||
}
|
||||
}
|
||||
_set.Append(", ").Append(_commonUtils.QuoteSqlName(cols.First().Column.Attribute.Name)).Append(" = ").Append(expt);
|
||||
return this;
|
||||
}
|
||||
public IUpdate<T1> SetRaw(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(sql)) return this;
|
||||
_set.Append(", ").Append(sql);
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this;
|
||||
}
|
||||
|
||||
public IUpdate<T1> Where(Expression<Func<T1, bool>> expression) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, expression?.Body));
|
||||
public IUpdate<T1> Where(string sql, object parms = null) {
|
||||
if (string.IsNullOrEmpty(sql)) return this;
|
||||
_where.Append(" AND (").Append(sql).Append(")");
|
||||
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||
return this;
|
||||
}
|
||||
public IUpdate<T1> Where(T1 item) => this.Where(new[] { item });
|
||||
public IUpdate<T1> Where(IEnumerable<T1> items) => this.Where(_commonUtils.WhereItems(_table, "", items));
|
||||
public IUpdate<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class => this.Where($"{(notExists ? "NOT " : "")}EXISTS({select.ToSql("1")})");
|
||||
|
||||
protected abstract void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys);
|
||||
protected abstract void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d);
|
||||
|
||||
public string ToSql() {
|
||||
if (_where.Length == 0) return null;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("UPDATE ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append(" SET ");
|
||||
|
||||
if (_set.Length > 0) { //指定 set 更新
|
||||
sb.Append(_set.ToString().Substring(2));
|
||||
|
||||
} else if (_source.Count == 1) { //保存 Source
|
||||
_paramsSource.Clear();
|
||||
var colidx = 0;
|
||||
foreach (var col in _table.Columns.Values) {
|
||||
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.CsName) == false) {
|
||||
if (colidx > 0) sb.Append(", ");
|
||||
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(_commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"));
|
||||
_commonUtils.AppendParamter(_paramsSource, null, _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(_source.First()) : DBNull.Value);
|
||||
++colidx;
|
||||
}
|
||||
}
|
||||
if (colidx == 0) return null;
|
||||
|
||||
} else if (_source.Count > 1) { //批量保存 Source
|
||||
if (_table.Primarys.Any() == false) return null;
|
||||
|
||||
var caseWhen = new StringBuilder();
|
||||
caseWhen.Append("CASE ");
|
||||
ToSqlCase(caseWhen, _table.Primarys);
|
||||
//if (_table.Primarys.Length > 1) caseWhen.Append("CONCAT(");
|
||||
//var pkidx = 0;
|
||||
//foreach (var pk in _table.Primarys) {
|
||||
// if (pkidx > 0) caseWhen.Append(", ");
|
||||
// caseWhen.Append(_commonUtils.QuoteSqlName(pk.Attribute.Name));
|
||||
// ++pkidx;
|
||||
//}
|
||||
//if (_table.Primarys.Length > 1) caseWhen.Append(")");
|
||||
var cw = caseWhen.Append(" ").ToString();
|
||||
|
||||
_paramsSource.Clear();
|
||||
var colidx = 0;
|
||||
foreach (var col in _table.Columns.Values) {
|
||||
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.CsName) == false) {
|
||||
if (colidx > 0) sb.Append(", ");
|
||||
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(cw);
|
||||
foreach (var d in _source) {
|
||||
sb.Append(" \r\nWHEN ");
|
||||
ToSqlWhen(sb, _table.Primarys, d);
|
||||
//if (_table.Primarys.Length > 1) sb.Append("CONCAT(");
|
||||
//pkidx = 0;
|
||||
//foreach (var pk in _table.Primarys) {
|
||||
// if (pkidx > 0) sb.Append(", ");
|
||||
// sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null));
|
||||
// ++pkidx;
|
||||
//}
|
||||
//if (_table.Primarys.Length > 1) sb.Append(")");
|
||||
sb.Append(" THEN ").Append(_commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"));
|
||||
_commonUtils.AppendParamter(_paramsSource, null, _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value);
|
||||
}
|
||||
sb.Append(" END");
|
||||
++colidx;
|
||||
}
|
||||
}
|
||||
if (colidx == 0) return null;
|
||||
} else
|
||||
return null;
|
||||
|
||||
sb.Append(" \r\nWHERE ").Append(_where.ToString().Substring(5));
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
119
FreeSql/Internal/CommonUtils.cs
Normal file
119
FreeSql/Internal/CommonUtils.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal {
|
||||
internal abstract class CommonUtils {
|
||||
|
||||
internal abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
|
||||
internal abstract DbParameter AppendParamter(List<DbParameter> _params, string parameterName, object value);
|
||||
internal abstract string FormatSql(string sql, params object[] args);
|
||||
internal abstract string QuoteSqlName(string name);
|
||||
internal abstract string QuoteParamterName(string name);
|
||||
internal abstract string IsNull(string sql, object value);
|
||||
|
||||
internal ICodeFirst CodeFirst { get; set; }
|
||||
internal TableInfo GetTableByEntity(Type entity) => Utils.GetTableByEntity(entity, this);
|
||||
|
||||
internal string WhereObject(TableInfo table, string aliasAndDot, object dywhere) {
|
||||
if (dywhere == null) return "";
|
||||
var type = dywhere.GetType();
|
||||
var primarys = table.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
||||
if (primarys.Length == 1 && type == primarys.First().CsType) {
|
||||
return $"{aliasAndDot}{this.QuoteSqlName(primarys.First().Attribute.Name)} = {this.FormatSql("{0}", dywhere)}";
|
||||
} else if (primarys.Length > 0 && type.FullName == table.Type.FullName) {
|
||||
var sb = new StringBuilder();
|
||||
var pkidx = 0;
|
||||
foreach (var pk in primarys) {
|
||||
var prop = type.GetProperty(pk.CsName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
|
||||
if (pkidx > 0) sb.Append(" AND ");
|
||||
sb.Append(aliasAndDot).Append(this.QuoteSqlName(pk.Attribute.Name));
|
||||
sb.Append(this.FormatSql(" = {0}", prop.GetValue(dywhere)));
|
||||
++pkidx;
|
||||
}
|
||||
return sb.ToString();
|
||||
} else if (dywhere is IEnumerable) {
|
||||
var sb = new StringBuilder();
|
||||
var ie = dywhere as IEnumerable;
|
||||
var ieidx = 0;
|
||||
foreach (var i in ie) {
|
||||
var fw = WhereObject(table, aliasAndDot, i);
|
||||
if (string.IsNullOrEmpty(fw)) continue;
|
||||
if (ieidx > 0) sb.Append(" OR ");
|
||||
sb.Append(fw);
|
||||
++ieidx;
|
||||
}
|
||||
return sb.ToString();
|
||||
} else {
|
||||
var sb = new StringBuilder();
|
||||
var ps = type.GetProperties();
|
||||
var psidx = 0;
|
||||
foreach (var p in ps) {
|
||||
if (table.Columns.TryGetValue(p.Name, out var trycol) == false) continue;
|
||||
if (psidx > 0) sb.Append(" AND ");
|
||||
sb.Append(aliasAndDot).Append(this.QuoteSqlName(trycol.Attribute.Name));
|
||||
sb.Append(this.FormatSql(" = {0}", p.GetValue(dywhere)));
|
||||
++psidx;
|
||||
}
|
||||
if (psidx == 0) return "";
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
internal string WhereItems<TEntity>(TableInfo table, string aliasAndDot, IEnumerable<TEntity> items) {
|
||||
if (items == null || items.Any() == false) return null;
|
||||
if (table.Primarys.Any() == false) return null;
|
||||
var its = items.Where(a => a != null).ToArray();
|
||||
|
||||
if (table.Primarys.Length == 1) {
|
||||
var sbin = new StringBuilder();
|
||||
sbin.Append(aliasAndDot).Append(this.QuoteSqlName(table.Primarys.First().Attribute.Name));
|
||||
var indt = its.Select(a => table.Properties.TryGetValue(table.Primarys.First().CsName, out var trycol) ? this.FormatSql("{0}", trycol.GetValue(a)) : null).Where(a => a != null).ToArray();
|
||||
if (indt.Any() == false) return null;
|
||||
if (indt.Length == 1) sbin.Append(" = ").Append(indt.First());
|
||||
else sbin.Append(" IN (").Append(string.Join(",", indt)).Append(")");
|
||||
return sbin.ToString();
|
||||
}
|
||||
var dicpk = its.Length > 5 ? new Dictionary<string, bool>() : null;
|
||||
var sb = its.Length > 5 ? null : new StringBuilder();
|
||||
var iidx = 0;
|
||||
foreach (var item in its) {
|
||||
var filter = "";
|
||||
for (var a = 0; a < table.Primarys.Length; a++) {
|
||||
if (table.Properties.TryGetValue(table.Primarys[a].CsName, out var trycol) == false) continue;
|
||||
filter += $" AND {aliasAndDot}{this.QuoteSqlName(table.Primarys[a].Attribute.Name)} = {this.FormatSql("{0}", trycol.GetValue(item))}";
|
||||
}
|
||||
if (string.IsNullOrEmpty(filter)) continue;
|
||||
if (sb != null) {
|
||||
sb.Append(" OR (");
|
||||
sb.Append(filter.Substring(5));
|
||||
sb.Append(")");
|
||||
++iidx;
|
||||
}
|
||||
if (dicpk != null) {
|
||||
filter = filter.Substring(5);
|
||||
if (dicpk.ContainsKey(filter) == false) {
|
||||
dicpk.Add(filter, true);
|
||||
++iidx;
|
||||
}
|
||||
}
|
||||
//++iidx;
|
||||
}
|
||||
if (iidx == 0) return null;
|
||||
if (sb == null) {
|
||||
sb = new StringBuilder();
|
||||
foreach (var fil in dicpk) {
|
||||
sb.Append(" OR (");
|
||||
sb.Append(fil.Key);
|
||||
sb.Append(")");
|
||||
}
|
||||
}
|
||||
return iidx == 1 ? sb.Remove(0, 5).Remove(sb.Length - 1, 1).ToString() : sb.Remove(0, 4).ToString();
|
||||
}
|
||||
}
|
||||
}
|
11
FreeSql/Internal/Model/ColumnInfo.cs
Normal file
11
FreeSql/Internal/Model/ColumnInfo.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
|
||||
namespace FreeSql.Internal.Model {
|
||||
class ColumnInfo {
|
||||
public TableInfo Table { get; set; }
|
||||
public string CsName { get; set; }
|
||||
public Type CsType { get; set; }
|
||||
public ColumnAttribute Attribute { get; set; }
|
||||
}
|
||||
}
|
14
FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs
Normal file
14
FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal.Model {
|
||||
class ReadAnonymousTypeInfo {
|
||||
public string CsName { get; set; }
|
||||
public ConstructorInfo Consturctor { get; set; }
|
||||
public ReadAnonymousTypeInfoConsturctorType ConsturctorType { get; set; }
|
||||
public List<ReadAnonymousTypeInfo> Childs = new List<ReadAnonymousTypeInfo>();
|
||||
}
|
||||
enum ReadAnonymousTypeInfoConsturctorType { Arguments, Properties }
|
||||
}
|
10
FreeSql/Internal/Model/SelectColumnInfo.cs
Normal file
10
FreeSql/Internal/Model/SelectColumnInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql.Internal.Model {
|
||||
class SelectColumnInfo {
|
||||
public ColumnInfo Column { get; set; }
|
||||
public SelectTableInfo Table { get; set; }
|
||||
}
|
||||
}
|
9
FreeSql/Internal/Model/SelectTableInfo.cs
Normal file
9
FreeSql/Internal/Model/SelectTableInfo.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace FreeSql.Internal.Model {
|
||||
class SelectTableInfo {
|
||||
public TableInfo Table { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public string On { get; set; }
|
||||
public SelectTableInfoType Type { get; set; }
|
||||
}
|
||||
enum SelectTableInfoType { From, LeftJoin, InnerJoin, RightJoin }
|
||||
}
|
18
FreeSql/Internal/Model/TableInfo.cs
Normal file
18
FreeSql/Internal/Model/TableInfo.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FreeSql.Internal.Model {
|
||||
class TableInfo {
|
||||
public Type Type { get; set; }
|
||||
public Dictionary<string, PropertyInfo> Properties { get; set; } = new Dictionary<string, PropertyInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||
public Dictionary<string, ColumnInfo> Columns { get; set; } = new Dictionary<string, ColumnInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||
public Dictionary<string, ColumnInfo> ColumnsByCs { get; set; } = new Dictionary<string, ColumnInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||
public ColumnInfo[] Primarys { get; set; }
|
||||
public string CsName { get; set; }
|
||||
public string DbName { get; set; }
|
||||
public string DbOldName { get; set; }
|
||||
public string SelectFilter { get; set; }
|
||||
public List<List<ColumnInfo>> Uniques { get; set; } = new List<List<ColumnInfo>>();
|
||||
}
|
||||
}
|
144
FreeSql/Internal/Utils.cs
Normal file
144
FreeSql/Internal/Utils.cs
Normal file
@ -0,0 +1,144 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace FreeSql.Internal {
|
||||
class Utils {
|
||||
|
||||
static ConcurrentDictionary<string, TableInfo> _cacheGetTableByEntity = new ConcurrentDictionary<string, TableInfo>();
|
||||
internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
|
||||
if (_cacheGetTableByEntity.TryGetValue(entity.FullName, out var trytb)) return trytb;
|
||||
if (common.CodeFirst.GetDbInfo(entity) != null) return null;
|
||||
|
||||
var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
|
||||
trytb = new TableInfo();
|
||||
trytb.Type = entity;
|
||||
trytb.Properties = entity.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
|
||||
trytb.CsName = entity.Name;
|
||||
trytb.DbName = tbattr?.Name ?? entity.Name;
|
||||
trytb.DbOldName = tbattr?.OldName;
|
||||
trytb.SelectFilter = tbattr?.SelectFilter;
|
||||
foreach (var p in trytb.Properties.Values) {
|
||||
var tp = common.CodeFirst.GetDbInfo(p.PropertyType);
|
||||
if (tp == null) continue;
|
||||
var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute ?? new ColumnAttribute {
|
||||
Name = p.Name,
|
||||
DbType = tp.Value.dbtypeFull,
|
||||
IsIdentity = false,
|
||||
IsNullable = tp.Value.isnullable ?? false,
|
||||
IsPrimary = false,
|
||||
};
|
||||
if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
|
||||
if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp.Value.dbtypeFull;
|
||||
if (colattr.DbType.IndexOf("NOT NULL") == -1 && tp.Value.isnullable == false) colattr.DbType += " NOT NULL";
|
||||
|
||||
var col = new ColumnInfo {
|
||||
Table = trytb,
|
||||
CsName = p.Name,
|
||||
CsType = p.PropertyType,
|
||||
Attribute = colattr
|
||||
};
|
||||
trytb.Columns.Add(colattr.Name, col);
|
||||
trytb.ColumnsByCs.Add(p.Name, col);
|
||||
}
|
||||
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
||||
_cacheGetTableByEntity.TryAdd(entity.FullName, trytb);
|
||||
return trytb;
|
||||
}
|
||||
|
||||
internal static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
|
||||
if (string.IsNullOrEmpty(sql) || obj == null) return new T[0];
|
||||
var ttype = typeof(T);
|
||||
var type = obj.GetType();
|
||||
if (type == ttype) return new[] { (T)Convert.ChangeType(obj, type) };
|
||||
var ret = new List<T>();
|
||||
var ps = type.GetProperties();
|
||||
foreach (var p in ps) {
|
||||
if (sql.IndexOf($"{paramPrefix}{p.Name}", StringComparison.CurrentCultureIgnoreCase) == -1) continue;
|
||||
var pvalue = p.GetValue(obj);
|
||||
if (p.PropertyType == ttype) ret.Add((T)Convert.ChangeType(pvalue, ttype));
|
||||
else ret.Add(constructorParamter(p.Name, p.PropertyType, pvalue));
|
||||
}
|
||||
return ret.ToArray();
|
||||
}
|
||||
|
||||
internal static (object value, int dataIndex) ExecuteArrayRowReadClassOrTuple(Type type, Dictionary<string, int> names, object[] row, int dataIndex = 0) {
|
||||
if (type.Namespace == "System" && (type.FullName == "System.String" || type.IsValueType)) { //值类型,或者元组
|
||||
bool isTuple = type.Name.StartsWith("ValueTuple`");
|
||||
if (isTuple) {
|
||||
var fs = type.GetFields();
|
||||
var types = new Type[fs.Length];
|
||||
var parms = new object[fs.Length];
|
||||
for (int a = 0; a < fs.Length; a++) {
|
||||
types[a] = fs[a].FieldType;
|
||||
var read = ExecuteArrayRowReadClassOrTuple(types[a], names, row, dataIndex);
|
||||
if (read.dataIndex > dataIndex) dataIndex = read.dataIndex;
|
||||
parms[a] = read.value;
|
||||
}
|
||||
var constructor = type.GetConstructor(types);
|
||||
return (constructor?.Invoke(parms), dataIndex);
|
||||
}
|
||||
return (dataIndex >= row.Length || row[dataIndex] == DBNull.Value ? null : Convert.ChangeType(row[dataIndex], type), dataIndex + 1);
|
||||
}
|
||||
if (type == typeof(object) && names != null) {
|
||||
dynamic expando = new System.Dynamic.ExpandoObject(); //动态类型字段 可读可写
|
||||
var expandodic = (IDictionary<string, object>)expando;
|
||||
foreach (var name in names)
|
||||
expandodic[Utils.GetCsName(name.Key)] = row[name.Value];
|
||||
return (expando, names.Count);
|
||||
}
|
||||
//类注入属性
|
||||
var consturct = type.GetConstructor(new Type[0]);
|
||||
var value = consturct.Invoke(new object[0]);
|
||||
var ps = type.GetProperties();
|
||||
foreach(var p in ps) {
|
||||
var tryidx = dataIndex;
|
||||
if (names != null && names.TryGetValue(p.Name, out tryidx) == false) continue;
|
||||
var read = ExecuteArrayRowReadClassOrTuple(p.PropertyType, names, row, tryidx);
|
||||
if (read.dataIndex > dataIndex) dataIndex = read.dataIndex;
|
||||
FillPropertyValue(value, p.Name, read.value);
|
||||
//p.SetValue(value, read.value);
|
||||
}
|
||||
return (value, dataIndex);
|
||||
}
|
||||
|
||||
internal static void FillPropertyValue(object info, string memberAccessPath, object value) {
|
||||
var current = info;
|
||||
PropertyInfo prop = null;
|
||||
var members = memberAccessPath.Split('.');
|
||||
for (var a = 0; a < members.Length; a++) {
|
||||
var type = current.GetType();
|
||||
prop = type.GetProperty(members[a], BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
|
||||
if (prop == null) throw new Exception(string.Concat(type.FullName, " 没有定义属性 ", members[a]));
|
||||
if (a < members.Length - 1) current = prop.GetValue(current);
|
||||
}
|
||||
if (value == null || value == DBNull.Value) {
|
||||
prop.SetValue(current, null, null);
|
||||
return;
|
||||
}
|
||||
var propType = prop.PropertyType;
|
||||
if (propType.FullName.StartsWith("System.Nullable`1[")) propType = propType.GenericTypeArguments.First();
|
||||
if (propType.IsEnum) {
|
||||
var valueStr = string.Concat(value);
|
||||
if (string.IsNullOrEmpty(valueStr) == false) prop.SetValue(current, Enum.Parse(propType, valueStr), null);
|
||||
return;
|
||||
}
|
||||
if (propType != value.GetType()) {
|
||||
prop.SetValue(current, Convert.ChangeType(value, propType), null);
|
||||
return;
|
||||
}
|
||||
prop.SetValue(current, value, null);
|
||||
}
|
||||
internal static string GetCsName(string name) {
|
||||
name = Regex.Replace(name.TrimStart('@'), @"[^\w]", "_");
|
||||
return char.IsLetter(name, 0) ? name : string.Concat("_", name);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user