|
@@ -1,17 +1,12 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Data;
|
|
|
-using System.Linq;
|
|
|
-using System.Linq.Expressions;
|
|
|
|
|
|
using Vit.Linq;
|
|
|
-using Vit.Linq.ExpressionTree.ComponentModel;
|
|
|
|
|
|
using Vitorm.Entity;
|
|
|
using Vitorm.Sql.DataReader.EntityReader;
|
|
|
using Vitorm.Sql.SqlTranslate;
|
|
|
-using Vitorm.Sql.Transaction;
|
|
|
-using Vitorm.StreamQuery;
|
|
|
|
|
|
namespace Vitorm.Sql
|
|
|
{
|
|
@@ -147,229 +142,10 @@ namespace Vitorm.Sql
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
- #region #2 Retrieve : Get Query
|
|
|
-
|
|
|
+ // #2 Retrieve : Get
|
|
|
public override Entity Get<Entity>(object keyValue) => DbSet<Entity>().Get(keyValue);
|
|
|
|
|
|
|
|
|
- public override IQueryable<Entity> Query<Entity>()
|
|
|
- {
|
|
|
- return QueryableBuilder.Build<Entity>(QueryExecutor, dbGroupName);
|
|
|
- }
|
|
|
-
|
|
|
- protected bool QueryIsFromSameDb(object query, Type elementType)
|
|
|
- {
|
|
|
- return dbGroupName == QueryableBuilder.GetQueryConfig(query as IQueryable) as string;
|
|
|
- }
|
|
|
- public Action<SqlDbContext, Expression, Type, object> AfterQuery;
|
|
|
- protected object QueryExecutor(Expression expression, Type expressionResultType)
|
|
|
- {
|
|
|
- object result = null;
|
|
|
- try
|
|
|
- {
|
|
|
- return result = ExecuteQuery(expression, expressionResultType);
|
|
|
- }
|
|
|
- finally
|
|
|
- {
|
|
|
- AfterQuery?.Invoke(this, expression, expressionResultType, result);
|
|
|
- }
|
|
|
- }
|
|
|
- public virtual SqlDbContext AutoDisposeAfterQuery()
|
|
|
- {
|
|
|
- AfterQuery += (_, _, _, _) => Dispose();
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- #region StreamReader
|
|
|
- public static StreamReader defaultStreamReader = new StreamReader();
|
|
|
- public StreamReader streamReader = defaultStreamReader;
|
|
|
- #endregion
|
|
|
-
|
|
|
- protected virtual object ExecuteQuery(Expression expression, Type expressionResultType)
|
|
|
- {
|
|
|
- // #1 convert to ExpressionNode
|
|
|
- ExpressionNode_Lambda node = convertService.ConvertToData_LambdaNode(expression, autoReduce: true, isArgument: QueryIsFromSameDb);
|
|
|
- //var strNode = Json.Serialize(node);
|
|
|
-
|
|
|
-
|
|
|
- // #2 convert to Stream
|
|
|
- var stream = streamReader.ReadFromNode(node);
|
|
|
- //var strStream = Json.Serialize(stream);
|
|
|
-
|
|
|
-
|
|
|
- // #3.1 ExecuteUpdate
|
|
|
- if (stream is StreamToUpdate streamToUpdate)
|
|
|
- {
|
|
|
- // get arg
|
|
|
- var resultEntityType = streamToUpdate.fieldsToUpdate.New_GetType();
|
|
|
- var arg = new QueryTranslateArgument(this, resultEntityType);
|
|
|
-
|
|
|
- var sql = sqlTranslateService.PrepareExecuteUpdate(arg, streamToUpdate);
|
|
|
-
|
|
|
- return Execute(sql: sql, param: arg.sqlParam);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // #3.3 Query
|
|
|
- // #3.3.1
|
|
|
- if (stream is not CombinedStream combinedStream) combinedStream = new CombinedStream("tmp") { source = stream };
|
|
|
-
|
|
|
- // #3.3.2 execute and read result
|
|
|
- switch (combinedStream.method)
|
|
|
- {
|
|
|
- case nameof(Orm_Extensions.ToExecuteString):
|
|
|
- {
|
|
|
- // ToExecuteString
|
|
|
-
|
|
|
- // get arg
|
|
|
- var arg = new QueryTranslateArgument(this, null);
|
|
|
-
|
|
|
- var sql = sqlTranslateService.PrepareQuery(arg, combinedStream);
|
|
|
- return sql;
|
|
|
- }
|
|
|
- case nameof(Orm_Extensions.ExecuteDelete):
|
|
|
- {
|
|
|
- // ExecuteDelete
|
|
|
-
|
|
|
- // get arg
|
|
|
- var entityType = (combinedStream.source as SourceStream)?.GetEntityType();
|
|
|
- var arg = new QueryTranslateArgument(this, entityType);
|
|
|
-
|
|
|
- var sql = sqlTranslateService.PrepareExecuteDelete(arg, combinedStream);
|
|
|
- var count = Execute(sql: sql, param: arg.sqlParam);
|
|
|
- return count;
|
|
|
- }
|
|
|
- case nameof(Queryable.FirstOrDefault) or nameof(Queryable.First) or nameof(Queryable.LastOrDefault) or nameof(Queryable.Last):
|
|
|
- {
|
|
|
- // get arg
|
|
|
- var resultEntityType = expression.Type;
|
|
|
- var arg = new QueryTranslateArgument(this, resultEntityType);
|
|
|
-
|
|
|
- var sql = sqlTranslateService.PrepareQuery(arg, combinedStream);
|
|
|
- using var reader = ExecuteReader(sql: sql, param: arg.sqlParam, useReadOnly: true);
|
|
|
- return arg.dataReader.ReadData(reader);
|
|
|
- }
|
|
|
- case nameof(Queryable.Count) or nameof(Queryable_Extensions.TotalCount):
|
|
|
- {
|
|
|
- return ExecuteQuery_Count(combinedStream);
|
|
|
- }
|
|
|
- case nameof(Queryable_Extensions.ToListAndTotalCount):
|
|
|
- {
|
|
|
- var resultEntityType = expression.Type.GetGenericArguments()?.FirstOrDefault()?.GetGenericArguments()?.FirstOrDefault();
|
|
|
- return ExecuteQuery_ToListAndTotalCount(combinedStream, resultEntityType);
|
|
|
- }
|
|
|
- case nameof(Enumerable.ToList):
|
|
|
- case "":
|
|
|
- case null:
|
|
|
- {
|
|
|
- // ToList
|
|
|
- var resultEntityType = expression.Type.GetGenericArguments()?.FirstOrDefault();
|
|
|
- return ExecuteQuery_ToList(combinedStream, resultEntityType);
|
|
|
- }
|
|
|
- }
|
|
|
- throw new NotSupportedException("not supported query type: " + combinedStream.method);
|
|
|
- }
|
|
|
-
|
|
|
- protected bool query_ToListAndTotalCount_InvokeInOneExecute = true;
|
|
|
- protected virtual object ExecuteQuery_ToListAndTotalCount(CombinedStream combinedStream, Type resultEntityType)
|
|
|
- {
|
|
|
- object list; int totalCount;
|
|
|
-
|
|
|
- if (query_ToListAndTotalCount_InvokeInOneExecute)
|
|
|
- {
|
|
|
- // get arg
|
|
|
- var arg = new QueryTranslateArgument(this, resultEntityType);
|
|
|
-
|
|
|
- string sqlToList, sqlCount;
|
|
|
- IDbDataReader dataReader;
|
|
|
- // #1 ToList
|
|
|
- {
|
|
|
- combinedStream.method = nameof(Enumerable.ToList);
|
|
|
- sqlToList = sqlTranslateService.PrepareQuery(arg, combinedStream);
|
|
|
- dataReader = arg.dataReader;
|
|
|
- }
|
|
|
-
|
|
|
- // #2 TotalCount
|
|
|
- {
|
|
|
- combinedStream.method = nameof(Enumerable.Count);
|
|
|
- (combinedStream.orders, combinedStream.skip, combinedStream.take) = (null, null, null);
|
|
|
-
|
|
|
- sqlCount = sqlTranslateService.PrepareCountQuery(arg, combinedStream);
|
|
|
- }
|
|
|
-
|
|
|
- // #3 read data
|
|
|
- {
|
|
|
- var sql = sqlCount + " ;\r\n" + sqlToList;
|
|
|
- using var reader = ExecuteReader(sql: sql, param: arg.sqlParam, useReadOnly: true);
|
|
|
- reader.Read();
|
|
|
- totalCount = Convert.ToInt32(reader[0]);
|
|
|
- reader.NextResult();
|
|
|
- list = dataReader.ReadData(reader);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- combinedStream.method = nameof(Enumerable.ToList);
|
|
|
- list = ExecuteQuery_ToList(combinedStream, resultEntityType);
|
|
|
-
|
|
|
- combinedStream.method = nameof(Queryable_Extensions.TotalCount);
|
|
|
- totalCount = ExecuteQuery_Count(combinedStream);
|
|
|
- }
|
|
|
-
|
|
|
- //combinedStream.method = nameof(Queryable_Extensions.ToListAndTotalCount);
|
|
|
-
|
|
|
- return new Func<object, int, (object, int)>(ValueTuple.Create<object, int>)
|
|
|
- .Method.GetGenericMethodDefinition()
|
|
|
- .MakeGenericMethod(list.GetType(), typeof(int))
|
|
|
- .Invoke(null, new[] { list, totalCount });
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Queryable.Count or Queryable_Extensions.TotalCount
|
|
|
- /// </summary>
|
|
|
- /// <param name="combinedStream"></param>
|
|
|
- /// <returns></returns>
|
|
|
- protected virtual int ExecuteQuery_Count(CombinedStream combinedStream)
|
|
|
- {
|
|
|
- // deal with skip and take , no need to pass to PrepareCountQuery
|
|
|
- var queryArg = (combinedStream.orders, combinedStream.skip, combinedStream.take);
|
|
|
- (combinedStream.orders, combinedStream.skip, combinedStream.take) = (null, null, null);
|
|
|
-
|
|
|
- // get arg
|
|
|
- var arg = new QueryTranslateArgument(this, null);
|
|
|
-
|
|
|
- var sql = sqlTranslateService.PrepareCountQuery(arg, combinedStream);
|
|
|
-
|
|
|
- var countValue = ExecuteScalar(sql: sql, param: arg.sqlParam, useReadOnly: true);
|
|
|
- var count = Convert.ToInt32(countValue);
|
|
|
- if (count > 0 && combinedStream.method == nameof(Queryable.Count))
|
|
|
- {
|
|
|
- if (queryArg.skip > 0) count = Math.Max(count - queryArg.skip.Value, 0);
|
|
|
-
|
|
|
- if (queryArg.take.HasValue)
|
|
|
- count = Math.Min(count, queryArg.take.Value);
|
|
|
- }
|
|
|
-
|
|
|
- (combinedStream.orders, combinedStream.skip, combinedStream.take) = queryArg;
|
|
|
- return count;
|
|
|
- }
|
|
|
-
|
|
|
- protected virtual object ExecuteQuery_ToList(CombinedStream combinedStream, Type resultEntityType)
|
|
|
- {
|
|
|
- var arg = new QueryTranslateArgument(this, resultEntityType);
|
|
|
-
|
|
|
- var sql = sqlTranslateService.PrepareQuery(arg, combinedStream);
|
|
|
-
|
|
|
- using var reader = ExecuteReader(sql: sql, param: arg.sqlParam, useReadOnly: true);
|
|
|
- return arg.dataReader.ReadData(reader);
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
-
|
|
|
|
|
|
// #3 Update: Update UpdateRange
|
|
|
public override int Update<Entity>(Entity entity) => DbSet<Entity>().Update(entity);
|
|
@@ -388,79 +164,9 @@ namespace Vitorm.Sql
|
|
|
|
|
|
|
|
|
|
|
|
- #region Transaction
|
|
|
- public virtual Func<SqlDbContext, ITransactionScope> createTransactionScope { set; get; }
|
|
|
- = (dbContext) => new SqlTransactionScope(dbContext);
|
|
|
- protected virtual ITransactionScope transactionScope { get; set; }
|
|
|
|
|
|
- public virtual IDbTransaction BeginTransaction()
|
|
|
- {
|
|
|
- transactionScope ??= createTransactionScope(this);
|
|
|
- return transactionScope.BeginTransaction();
|
|
|
- }
|
|
|
- public virtual IDbTransaction GetCurrentTransaction() => transactionScope?.GetCurrentTransaction();
|
|
|
|
|
|
- #endregion
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- #region Execute
|
|
|
- protected SqlExecutor sqlExecutor;
|
|
|
- public static int? defaultCommandTimeout;
|
|
|
- public int? commandTimeout;
|
|
|
-
|
|
|
- public virtual int ExecuteWithTransaction(string sql, IDictionary<string, object> param = null, IDbTransaction transaction = null)
|
|
|
- {
|
|
|
- commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
|
|
|
-
|
|
|
- return sqlExecutor.Execute(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
|
|
|
- }
|
|
|
-
|
|
|
- public virtual int Execute(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
|
|
|
- {
|
|
|
- commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
|
|
|
- var transaction = GetCurrentTransaction();
|
|
|
-
|
|
|
- if (useReadOnly && transaction == null)
|
|
|
- {
|
|
|
- return sqlExecutor.Execute(readOnlyDbConnection, sql, param: param, commandTimeout: commandTimeout);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return sqlExecutor.Execute(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- public virtual IDataReader ExecuteReader(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
|
|
|
- {
|
|
|
- commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
|
|
|
- var transaction = GetCurrentTransaction();
|
|
|
-
|
|
|
- if (useReadOnly && transaction == null)
|
|
|
- {
|
|
|
- return sqlExecutor.ExecuteReader(readOnlyDbConnection, sql, param: param, commandTimeout: commandTimeout);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return sqlExecutor.ExecuteReader(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public virtual object ExecuteScalar(string sql, IDictionary<string, object> param = null, int? commandTimeout = null, bool useReadOnly = false)
|
|
|
- {
|
|
|
- commandTimeout ??= this.commandTimeout ?? defaultCommandTimeout;
|
|
|
- var transaction = GetCurrentTransaction();
|
|
|
-
|
|
|
- if (useReadOnly && transaction == null)
|
|
|
- {
|
|
|
- return sqlExecutor.ExecuteScalar(readOnlyDbConnection, sql, param: param, commandTimeout: commandTimeout);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return sqlExecutor.ExecuteScalar(dbConnection, sql, param: param, transaction: transaction, commandTimeout: commandTimeout);
|
|
|
- }
|
|
|
- }
|
|
|
- #endregion
|
|
|
|
|
|
}
|
|
|
}
|