1538 lines
63 KiB
C#
1538 lines
63 KiB
C#
|
|
using APT.Infrastructure.Core;
|
|||
|
|
using APT.Infrastructure.Utility;
|
|||
|
|
using Microsoft.EntityFrameworkCore;
|
|||
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||
|
|
using Microsoft.EntityFrameworkCore.Internal;
|
|||
|
|
using Microsoft.EntityFrameworkCore.Metadata;
|
|||
|
|
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
|||
|
|
using Microsoft.EntityFrameworkCore.Query;
|
|||
|
|
using Microsoft.EntityFrameworkCore.Storage;
|
|||
|
|
using Microsoft.Extensions.Logging;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.ComponentModel.DataAnnotations;
|
|||
|
|
using System.Data;
|
|||
|
|
using System.Data.Common;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Linq.Expressions;
|
|||
|
|
using System.Reflection;
|
|||
|
|
using System.Runtime.InteropServices.ComTypes;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
using System.Linq.Dynamic.Core;
|
|||
|
|
using System.Collections.Concurrent;
|
|||
|
|
using APT.Infrastructure.EF.Infrastructure;
|
|||
|
|
using APT.Infrastructure.Api;
|
|||
|
|
using System.Text.RegularExpressions;
|
|||
|
|
using Microsoft.Data.SqlClient;
|
|||
|
|
//using Npgsql;
|
|||
|
|
using APT.Infrastructure.Core.Refctor;
|
|||
|
|
using System.ComponentModel;
|
|||
|
|
|
|||
|
|
namespace APT.Infrastructure.EF
|
|||
|
|
{
|
|||
|
|
public class EfDbContext : TenantBaseDbContext, IUnitOfWork, IDependency
|
|||
|
|
{
|
|||
|
|
private readonly string namedConnection;
|
|||
|
|
|
|||
|
|
private const string dbsRedisKey = "DbConn_RedisKey";
|
|||
|
|
|
|||
|
|
private static IConnectionResolver _connectionResolver;
|
|||
|
|
private static IConnectionResolver ConnectionResolver
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
if (_connectionResolver == null)
|
|||
|
|
{
|
|||
|
|
ServiceLocator serviceLocator = ServiceLocator.Instance;
|
|||
|
|
_connectionResolver = serviceLocator.GetService<IConnectionResolver>();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
return _connectionResolver;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//public static Action<string> SQL_LOG { get; set; }
|
|||
|
|
int _TranscationLocker = 0;
|
|||
|
|
|
|||
|
|
IDbContextTransaction _dbContextTransaction;
|
|||
|
|
|
|||
|
|
private static EFModel _efModel;
|
|||
|
|
|
|||
|
|
|
|||
|
|
#region ctor.
|
|||
|
|
public EfDbContext() : base()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化一个<see cref="CodeFirstDbContext"/>类型的新实例
|
|||
|
|
/// </summary>
|
|||
|
|
//<summary>
|
|||
|
|
// 使用连接名称或连接字符串 初始化一个<see cref= "CodeFirstDbContext" /> 类型的新实例
|
|||
|
|
// </ summary >
|
|||
|
|
public EfDbContext(string nameOrConnectionString) : base()
|
|||
|
|
{
|
|||
|
|
this.namedConnection = nameOrConnectionString;
|
|||
|
|
}
|
|||
|
|
public TenantInfo TenantInfo => tenantInfo;
|
|||
|
|
|
|||
|
|
private readonly TenantInfo tenantInfo;
|
|||
|
|
|
|||
|
|
|
|||
|
|
public EfDbContext(DbContextOptions<EfDbContext> options, TenantInfo tenant, IServiceProvider serviceProvider)
|
|||
|
|
: base(options, tenant, serviceProvider)
|
|||
|
|
{
|
|||
|
|
this.tenantInfo = tenant;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region IUnitOfWork 成员
|
|||
|
|
|
|||
|
|
public string ConnectionString
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
return ConfigurationManager.ConnectionStrings[namedConnection] ?? namedConnection;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public int ExecuteSqlCommand(string sql, params object[] parameters)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
return ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sql, parameters);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters)
|
|||
|
|
{
|
|||
|
|
return Database.ExecuteSqlRaw(sql, parameters);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ExecuteReader(string sql, ReaderColumn[] readerColumns, Action<DbDataReader> readerAction)
|
|||
|
|
{
|
|||
|
|
ExecuteReader(sql, readerColumns, null, readerAction);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ExecuteReader(string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action<DbDataReader> readerAction)
|
|||
|
|
{
|
|||
|
|
ExecuteReader(CommandType.Text, sql, readerColumns, parameters, readerAction);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ExecuteReader(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action<DbDataReader> readerAction)
|
|||
|
|
{
|
|||
|
|
var concurrencyDetector = Database.GetService<IConcurrencyDetector>();
|
|||
|
|
using (concurrencyDetector.EnterCriticalSection())
|
|||
|
|
{
|
|||
|
|
IReadOnlyDictionary<string, object> paramValues = null;
|
|||
|
|
IRelationalCommand relationalCommand = GetRelationComman(sql, parameters, out paramValues);
|
|||
|
|
|
|||
|
|
var paramObject = new RelationalCommandParameterObject(
|
|||
|
|
Database.GetService<IRelationalConnection>(),
|
|||
|
|
paramValues, readerColumns,
|
|||
|
|
this,
|
|||
|
|
null
|
|||
|
|
);
|
|||
|
|
var relR = relationalCommand
|
|||
|
|
.ExecuteReader(
|
|||
|
|
paramObject);
|
|||
|
|
if (relR != null && readerAction != null)
|
|||
|
|
readerAction(relR.DbDataReader);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public int ExecuteNonQuery(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters)
|
|||
|
|
{
|
|||
|
|
var concurrencyDetector = Database.GetService<IConcurrencyDetector>();
|
|||
|
|
using (concurrencyDetector.EnterCriticalSection())
|
|||
|
|
{
|
|||
|
|
IReadOnlyDictionary<string, object> paramValues = null;
|
|||
|
|
IRelationalCommand relationalCommand = GetRelationComman(sql, parameters, out paramValues);
|
|||
|
|
|
|||
|
|
var paramObject = new RelationalCommandParameterObject(
|
|||
|
|
Database.GetService<IRelationalConnection>(),
|
|||
|
|
paramValues, readerColumns,
|
|||
|
|
this,
|
|||
|
|
null
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
var dr = relationalCommand
|
|||
|
|
.ExecuteNonQuery(paramObject);
|
|||
|
|
|
|||
|
|
return dr;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private IRelationalCommand GetRelationComman(string sql, object[] parameters, out IReadOnlyDictionary<string, object> paramValues)
|
|||
|
|
{
|
|||
|
|
paramValues = null;
|
|||
|
|
IRelationalCommand relationalCommand = null;
|
|||
|
|
if (parameters != null && parameters.Any())
|
|||
|
|
{
|
|||
|
|
var rawSqlCommand = Database
|
|||
|
|
.GetService<IRawSqlCommandBuilder>()
|
|||
|
|
.Build(sql, parameters);
|
|||
|
|
relationalCommand = rawSqlCommand
|
|||
|
|
.RelationalCommand;
|
|||
|
|
paramValues = rawSqlCommand.ParameterValues;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
relationalCommand = Database
|
|||
|
|
.GetService<IRawSqlCommandBuilder>()
|
|||
|
|
.Build(sql);
|
|||
|
|
}
|
|||
|
|
return relationalCommand;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public IEnumerable SqlQuery(Type elementType, string sql, ReaderColumn[] readCloums, params object[] parameters)
|
|||
|
|
{
|
|||
|
|
var concurrencyDetector = Database.GetService<IConcurrencyDetector>();
|
|||
|
|
using (concurrencyDetector.EnterCriticalSection())
|
|||
|
|
{
|
|||
|
|
IReadOnlyDictionary<string, object> paramValues = null;
|
|||
|
|
IRelationalCommand relationalCommand = GetRelationComman(sql, parameters, out paramValues);
|
|||
|
|
|
|||
|
|
var paramObject = new RelationalCommandParameterObject(
|
|||
|
|
Database.GetService<IRelationalConnection>(),
|
|||
|
|
paramValues, readCloums,
|
|||
|
|
this,
|
|||
|
|
null
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
var dr = relationalCommand
|
|||
|
|
.ExecuteReader(paramObject);
|
|||
|
|
|
|||
|
|
return dr.DbDataReader;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region GetTreeOrderEntities
|
|||
|
|
public IEnumerable<TreeNode<T>> GetTreeOrderEntities<T>(Expression<Func<T, bool>> expression, BaseFilter filter,
|
|||
|
|
Expression<Func<T, bool>> orgExpress, out List<T> resultList, bool isTracking = true,
|
|||
|
|
params string[] paths) where T : TreeEntityBase<T>, new()
|
|||
|
|
{
|
|||
|
|
List<T> allData = new List<T>();
|
|||
|
|
//List<T> data = new List<T>();
|
|||
|
|
if (filter == null)
|
|||
|
|
{
|
|||
|
|
filter = new BaseFilter();
|
|||
|
|
}
|
|||
|
|
var selectFields = filter.SelectField;
|
|||
|
|
if (selectFields.Any())
|
|||
|
|
{
|
|||
|
|
if (!string.IsNullOrEmpty(filter.Sort))
|
|||
|
|
{
|
|||
|
|
if (!selectFields.Contains(filter.Sort))
|
|||
|
|
selectFields = selectFields.Append(filter.Sort).ToList();
|
|||
|
|
}
|
|||
|
|
else if (filter.Orders != null && filter.Orders.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var o in filter.Orders)
|
|||
|
|
{
|
|||
|
|
if (!selectFields.Contains(o.Field))
|
|||
|
|
selectFields = selectFields.Append(o.Field).ToList();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
selectFields = selectFields.Append("ORG_ID").ToList();
|
|||
|
|
}
|
|||
|
|
if (filter.IsParentData)
|
|||
|
|
{
|
|||
|
|
if (selectFields.Any() && !selectFields.Contains("ORG_ID"))
|
|||
|
|
selectFields = selectFields.Append("ORG_ID").ToList();
|
|||
|
|
allData = this.GetEntities<T>(orgExpress, selectFields.ToArray(), isTracking, paths).ToList();
|
|||
|
|
resultList = allData.AsQueryable().Where(expression).ToList();
|
|||
|
|
var dataIds = resultList.Select(i => i.ID).ToArray();
|
|||
|
|
AddParentData(allData, resultList, dataIds);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
resultList = this.GetEntities(expression, selectFields.ToArray(), isTracking, paths).ToList();
|
|||
|
|
}
|
|||
|
|
//有条件,需要再次查询,查询结果的父级
|
|||
|
|
var ids = resultList.Select(i => i.ID).ToArray();
|
|||
|
|
var parentData = resultList.Where(i => !ids.Contains(i.PARENT_ID ?? Guid.Empty) || i.PARENT_ID == null).ToList();
|
|||
|
|
|
|||
|
|
List<TreeNode<T>> treeNodes = new List<TreeNode<T>>();
|
|||
|
|
foreach (var d in parentData)
|
|||
|
|
{
|
|||
|
|
var node = new TreeNode<T>();
|
|||
|
|
node.Node = d;
|
|||
|
|
node.Children = new List<TreeNode<T>>();
|
|||
|
|
node.Level = filter.Level < 0 ? 0 : filter.Level;
|
|||
|
|
node.IsLeaf = filter.Level < 0 ? true : d.IS_LEAF;
|
|||
|
|
if (filter.Level < 0)//<0 取全部数据,>=0 表示异步取数
|
|||
|
|
{
|
|||
|
|
var childNodes = resultList.Where(i => i.PARENT_ID == d.ID).ToList();
|
|||
|
|
if (childNodes.Any())
|
|||
|
|
{
|
|||
|
|
node.IsLeaf = false;
|
|||
|
|
InitFullTree(resultList, childNodes, node, node.Level + 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
treeNodes.Add(node);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ReSort(treeNodes, filter);
|
|||
|
|
return treeNodes;
|
|||
|
|
}
|
|||
|
|
private static void InitFullTree<T>(List<T> data, List<T> childNodeList, TreeNode<T> theNode, int level) where T : TreeEntityBase<T>, new()
|
|||
|
|
{
|
|||
|
|
foreach (var d in childNodeList)
|
|||
|
|
{
|
|||
|
|
var node = new TreeNode<T>();
|
|||
|
|
node.Node = d;
|
|||
|
|
node.Children = new List<TreeNode<T>>();
|
|||
|
|
node.Level = level;
|
|||
|
|
node.IsLeaf = true;
|
|||
|
|
var childNodes = data.Where(i => i.PARENT_ID == d.ID).ToList();
|
|||
|
|
if (childNodes.Any())
|
|||
|
|
{
|
|||
|
|
node.IsLeaf = false;
|
|||
|
|
InitFullTree(data, childNodes, node, level + 1);
|
|||
|
|
}
|
|||
|
|
theNode.Children.Add(node);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private static void AddParentData<T>(List<T> allData, List<T> data, Guid[] dataIds) where T : TreeEntityBase<T>, new()
|
|||
|
|
{
|
|||
|
|
var emptyDataIds = data.Where(i => i.PARENT_ID != null
|
|||
|
|
&& !dataIds.Contains(i.PARENT_ID ?? Guid.Empty)).Select(i => i.PARENT_ID ?? Guid.Empty).ToArray();
|
|||
|
|
if (emptyDataIds.Any())
|
|||
|
|
{
|
|||
|
|
var emptyData = allData.Where(i => emptyDataIds.Contains(i.ID));
|
|||
|
|
if (emptyData.Any())
|
|||
|
|
{
|
|||
|
|
data.AddRange(emptyData);
|
|||
|
|
dataIds = data.Select(i => i.ID).ToArray();
|
|||
|
|
AddParentData(allData, data, dataIds);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
private static void ReSort<T>(List<TreeNode<T>> treeNodes, BaseFilter filter) where T : TreeEntityBase<T>, new()
|
|||
|
|
{
|
|||
|
|
SortBy<T>(filter, treeNodes);
|
|||
|
|
foreach (var node in treeNodes)
|
|||
|
|
{
|
|||
|
|
if (node.Children != null && node.Children.Any())
|
|||
|
|
{
|
|||
|
|
ReSort(node.Children, filter);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private static IList<T> SortBy<T>(BaseFilter filter, IList<T> parentData) where T : TreeEntityBase<T>, new()
|
|||
|
|
{
|
|||
|
|
if (!string.IsNullOrEmpty(filter.Sort))
|
|||
|
|
{
|
|||
|
|
if (filter.Order == DbOrder.ASC)
|
|||
|
|
parentData = parentData.AsQueryable().OrderBy(filter.Sort + " asc").ToList();
|
|||
|
|
else
|
|||
|
|
parentData = parentData.AsQueryable().OrderBy(filter.Sort + " desc").ToList();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (filter.Orders != null && filter.Orders.Any())
|
|||
|
|
{
|
|||
|
|
var sortSql = "";
|
|||
|
|
foreach (var o in filter.Orders)
|
|||
|
|
{
|
|||
|
|
sortSql += o.Field + (o.Order == DbOrder.ASC ? " asc," : " desc,");
|
|||
|
|
}
|
|||
|
|
sortSql = sortSql.TrimEnd(',');
|
|||
|
|
parentData = parentData.AsQueryable().OrderBy(sortSql).ToList();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return parentData;
|
|||
|
|
}
|
|||
|
|
private static IList<TreeNode<T>> SortBy<T>(BaseFilter filter, List<TreeNode<T>> treeNodes) where T : TreeEntityBase<T>, new()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(filter.Sort))
|
|||
|
|
{
|
|||
|
|
if (filter.Order == DbOrder.ASC)
|
|||
|
|
{
|
|||
|
|
var orderyNodes = treeNodes.AsQueryable().OrderBy("Node." + filter.Sort + " asc").ToList();
|
|||
|
|
treeNodes.Clear();
|
|||
|
|
treeNodes.AddRange(orderyNodes);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
var orderyNodes = treeNodes.AsQueryable().OrderBy("Node." + filter.Sort + " desc").ToList();
|
|||
|
|
treeNodes.Clear();
|
|||
|
|
treeNodes.AddRange(orderyNodes);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (filter.Orders != null && filter.Orders.Any())
|
|||
|
|
{
|
|||
|
|
var sortSql = "";
|
|||
|
|
foreach (var o in filter.Orders)
|
|||
|
|
{
|
|||
|
|
sortSql += "Node." + o.Field + (o.Order == DbOrder.ASC ? " asc," : " desc,");
|
|||
|
|
}
|
|||
|
|
sortSql = sortSql.TrimEnd(',');
|
|||
|
|
var orderyNodes = treeNodes.AsQueryable().OrderBy(sortSql).ToList();
|
|||
|
|
treeNodes.Clear();
|
|||
|
|
treeNodes.AddRange(orderyNodes);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return treeNodes;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
public override int SaveChanges()
|
|||
|
|
{
|
|||
|
|
var entities = from e in ChangeTracker.Entries()
|
|||
|
|
where e.State == EntityState.Added
|
|||
|
|
|| e.State == EntityState.Modified
|
|||
|
|
select e.Entity;
|
|||
|
|
var delEntities = from e in ChangeTracker.Entries()
|
|||
|
|
where e.State == EntityState.Deleted
|
|||
|
|
select e.Entity;
|
|||
|
|
List<string> typeNames = new List<string>();
|
|||
|
|
Dictionary<Type, Guid> DicInitTree = new Dictionary<Type, Guid>();
|
|||
|
|
var isReInitTree = false;
|
|||
|
|
foreach (var entity in entities)
|
|||
|
|
{
|
|||
|
|
var validationContext = new ValidationContext(entity);
|
|||
|
|
|
|||
|
|
var dbExceptions = new List<ValidationException>();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
Validator.ValidateObject(entity, validationContext);
|
|||
|
|
}
|
|||
|
|
catch (ValidationException dbEx)
|
|||
|
|
{
|
|||
|
|
var errorBuilder = new StringBuilder();
|
|||
|
|
errorBuilder.AppendLine(dbEx.Message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (dbExceptions.Count > 0)
|
|||
|
|
{
|
|||
|
|
var errorBuilder = new StringBuilder();
|
|||
|
|
dbExceptions.ForEach(ve => errorBuilder.AppendLine(ve.Message));
|
|||
|
|
|
|||
|
|
throw new DomainException(errorBuilder.ToString());
|
|||
|
|
}
|
|||
|
|
var type = entity.GetType();
|
|||
|
|
if (!typeNames.Contains(type.Name))
|
|||
|
|
{
|
|||
|
|
typeNames.Add(type.Name);
|
|||
|
|
if (type.BaseType.Name.StartsWith("TreeEntityBase`1") || type.BaseType.Name.StartsWith("MesTreeEntityBase"))
|
|||
|
|
{
|
|||
|
|
isReInitTree = true;
|
|||
|
|
var orgId = type.GetProperty("ORG_ID").GetValue(entity);
|
|||
|
|
if (orgId == null)
|
|||
|
|
orgId = Guid.Empty;
|
|||
|
|
DicInitTree.TryAdd(type, Guid.Parse(orgId.ToString()));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
foreach (var entity in delEntities)
|
|||
|
|
{
|
|||
|
|
var type = entity.GetType();
|
|||
|
|
if (!typeNames.Contains(type.Name))
|
|||
|
|
{
|
|||
|
|
typeNames.Add(type.Name);
|
|||
|
|
if (entity is MesTreeEntityBase)
|
|||
|
|
{
|
|||
|
|
isReInitTree = true;
|
|||
|
|
DicInitTree.TryAdd(type, Guid.Parse(type.GetProperty("ORG_ID").GetValue(entity).ToString()));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var intResult = base.SaveChanges();
|
|||
|
|
if (isReInitTree)
|
|||
|
|
{
|
|||
|
|
foreach (var dic in DicInitTree)
|
|||
|
|
{
|
|||
|
|
MethodInfo methodInfo = this.GetType().GetMethod("InitTreeData",
|
|||
|
|
BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
|
|||
|
|
methodInfo.MakeGenericMethod(new Type[] { dic.Key }).
|
|||
|
|
Invoke(this, new object[] { dic.Value });
|
|||
|
|
}
|
|||
|
|
var ret = base.SaveChanges();
|
|||
|
|
}
|
|||
|
|
return intResult;
|
|||
|
|
}
|
|||
|
|
catch (DbUpdateException dbEx)
|
|||
|
|
{
|
|||
|
|
HandleDbUpdateException(dbEx);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
throw ex;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 统一处理数据库报的异常
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="ex">DbUpdateException</param>
|
|||
|
|
public void HandleDbUpdateException(DbUpdateException ex)
|
|||
|
|
{
|
|||
|
|
var dbType = this.DBType();
|
|||
|
|
if (ex.Entries.Count == 1)
|
|||
|
|
{
|
|||
|
|
var entries = ex.Entries.FirstOrDefault();
|
|||
|
|
var data = entries.Entity;
|
|||
|
|
ExcetionTrow(ex, dbType, data);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (dbType == DataBaseType.Postgresql)
|
|||
|
|
{
|
|||
|
|
//var errMsg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
|
|||
|
|
//if (ex.GetBaseException() is NpgsqlException pgException)
|
|||
|
|
//{
|
|||
|
|
// var p = pgException.GetType().GetProperty("Statement");
|
|||
|
|
// if (p != null)
|
|||
|
|
// {
|
|||
|
|
// object stateMent = p.GetValue(pgException);
|
|||
|
|
// var parameterProp = p.PropertyType.GetProperty("InputParameters");
|
|||
|
|
// if (parameterProp != null)
|
|||
|
|
// {
|
|||
|
|
// var parameters = parameterProp.GetValue(stateMent) as List<Npgsql.NpgsqlParameter>;
|
|||
|
|
// if (parameters != null && parameters.Any())
|
|||
|
|
// {
|
|||
|
|
// var idstr = parameters.FirstOrDefault().NpgsqlValue.ToString();
|
|||
|
|
// foreach (var e in ex.Entries)
|
|||
|
|
// {
|
|||
|
|
// var entity = e.Entity;
|
|||
|
|
// if (entity.GetType().GetProperty("ID").GetValue(entity).ToString() == idstr)
|
|||
|
|
// {
|
|||
|
|
// ExcetionTrow(ex, dbType, entity);
|
|||
|
|
// break;
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// }
|
|||
|
|
// throw new DomainException(errMsg);
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
throw new DomainException(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ExcetionTrow(DbUpdateException ex, DataBaseType dbType, object data)
|
|||
|
|
{
|
|||
|
|
var tableName = data.GetType().Name;
|
|||
|
|
//var keys = GetModelForeignKey(tableName); //获取外键信息
|
|||
|
|
var id = data.GetType().GetProperty("ID").GetValue(data);
|
|||
|
|
if (dbType == DataBaseType.Oracle)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
else if (dbType == DataBaseType.MySQL)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
//else if (dbType == DataBaseType.Postgresql)
|
|||
|
|
//{
|
|||
|
|
// if (ex.GetBaseException() is NpgsqlException pgException)
|
|||
|
|
// {
|
|||
|
|
// var code = pgException.Data["SqlState"].ToString();
|
|||
|
|
// var type = ReflectHelper.FindTypeInCurrentDomain(tableName);
|
|||
|
|
// var props = type.GetProperties();
|
|||
|
|
// switch (code)
|
|||
|
|
// {
|
|||
|
|
// //case 547:
|
|||
|
|
// // //外键报错
|
|||
|
|
// // //errMsg = ForeignKeyErrorFormatter(sqlException);
|
|||
|
|
// // break;
|
|||
|
|
// //case 2601:
|
|||
|
|
// case "23505":
|
|||
|
|
// if (type != null)
|
|||
|
|
// {
|
|||
|
|
// //唯一约束报错
|
|||
|
|
// //var tableName = pgException.Data["TableName"].ToString();
|
|||
|
|
// var constraintName = pgException.Data["ConstraintName"].ToString();
|
|||
|
|
// var clomsMsg = "存在重复键值数据!";
|
|||
|
|
// if (constraintName.StartsWith("PK"))//主键
|
|||
|
|
// {
|
|||
|
|
// clomsMsg = "主键重复。";
|
|||
|
|
// }
|
|||
|
|
// else
|
|||
|
|
// {
|
|||
|
|
// var startIndex = constraintName.IndexOf(tableName);
|
|||
|
|
// if (startIndex >= 0)
|
|||
|
|
// {
|
|||
|
|
// var temp = constraintName.Substring(startIndex + tableName.Length).Trim('_');
|
|||
|
|
// //var cloums = temp.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
|
|||
|
|
|
|||
|
|
// bool check = true;
|
|||
|
|
// while (check && temp.Length > 0)
|
|||
|
|
// {
|
|||
|
|
// check = false;
|
|||
|
|
// foreach (var c in props)
|
|||
|
|
// {
|
|||
|
|
// if (c.Name == "ID")
|
|||
|
|
// continue;
|
|||
|
|
// if (temp.StartsWith(c.Name))
|
|||
|
|
// {
|
|||
|
|
// //var fKey = keys.FirstOrDefault(i => i.ForeignFieldName == c.Name);
|
|||
|
|
// //if (fKey == null)
|
|||
|
|
// //{
|
|||
|
|
// clomsMsg = GetProMsgVal(data, clomsMsg, c);
|
|||
|
|
// //}
|
|||
|
|
// //else
|
|||
|
|
// //{
|
|||
|
|
// // var navName = fKey.ForeignNavName;
|
|||
|
|
// // var navPro = props.FirstOrDefault(i => i.Name == navName);
|
|||
|
|
// // if (navPro != null)
|
|||
|
|
// // {
|
|||
|
|
// // clomsMsg = GetProMsgVal(data, clomsMsg, navPro);
|
|||
|
|
// // }
|
|||
|
|
// //}
|
|||
|
|
// temp = temp.Substring(c.Name.Length).Trim('_');
|
|||
|
|
// check = true;
|
|||
|
|
// break;
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// clomsMsg = clomsMsg + "[ID]:" + id;
|
|||
|
|
// throw new DomainException(clomsMsg);
|
|||
|
|
// }
|
|||
|
|
// break;
|
|||
|
|
// case "23503":
|
|||
|
|
// if (type != null)
|
|||
|
|
// {
|
|||
|
|
// var constraintName = pgException.Data["ConstraintName"].ToString();
|
|||
|
|
// var clomsMsg = "外键字段数据异常!";
|
|||
|
|
// if (constraintName.StartsWith("FK"))//外键FK_T_BD_ENERGY_TYPE_T_FM_ENUM_ITEM_UNIT_ENUM_ITEM_ID
|
|||
|
|
// {
|
|||
|
|
// var tmp = constraintName.Replace("FK_", "").Replace(tableName + "_", "");
|
|||
|
|
// var keys = GetModelForeignKey(tableName);
|
|||
|
|
// if (keys != null && keys.Any())
|
|||
|
|
// {
|
|||
|
|
// foreach (var key in keys)
|
|||
|
|
// {
|
|||
|
|
// tmp = tmp.Replace(key.ForeignTableName + "_", "");
|
|||
|
|
// }
|
|||
|
|
// //if (tmp.Length > 0)
|
|||
|
|
// //{
|
|||
|
|
// // clomsMsg += "[" + tmp + "]";
|
|||
|
|
// //}
|
|||
|
|
// var fkProp = data.GetType().GetProperty(tmp);
|
|||
|
|
// if (fkProp != null)
|
|||
|
|
// {
|
|||
|
|
// clomsMsg = GetProMsgVal(data, clomsMsg, fkProp);
|
|||
|
|
// }
|
|||
|
|
// else
|
|||
|
|
// {
|
|||
|
|
// clomsMsg += ex.InnerException.Message;
|
|||
|
|
// }
|
|||
|
|
// clomsMsg = clomsMsg.TrimEnd(',');
|
|||
|
|
// throw new DomainException(clomsMsg);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// break;
|
|||
|
|
// case "22001":
|
|||
|
|
// {
|
|||
|
|
// var msg = pgException.Message + ".";
|
|||
|
|
// foreach (var c in props)
|
|||
|
|
// {
|
|||
|
|
// var lengthAttribute = c.GetAttribute<DataFieldLengthAttribute>();
|
|||
|
|
// if (lengthAttribute != null)
|
|||
|
|
// {
|
|||
|
|
// var val = c.GetValue(data);
|
|||
|
|
// if (val != null && lengthAttribute.Length < val.ToString().Length)
|
|||
|
|
// msg += $"[{c.Name}]:{val},";
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
// msg = msg + "[ID]:" + id;
|
|||
|
|
// throw new DomainException(msg);
|
|||
|
|
// }
|
|||
|
|
// break;
|
|||
|
|
// default:
|
|||
|
|
// //自定义报错
|
|||
|
|
// //errMsg = CustomErrorFormatter(sqlException);
|
|||
|
|
// break;
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
else if (dbType == DataBaseType.SQL)
|
|||
|
|
{
|
|||
|
|
if (ex.GetBaseException() is SqlException sqlException)
|
|||
|
|
{
|
|||
|
|
var errMsg = "";
|
|||
|
|
switch (sqlException.Number)
|
|||
|
|
{
|
|||
|
|
case 547:
|
|||
|
|
//外键报错
|
|||
|
|
errMsg = sqlException.Message;
|
|||
|
|
break;
|
|||
|
|
case 2601:
|
|||
|
|
case 2627:
|
|||
|
|
//唯一约束报错
|
|||
|
|
errMsg = sqlException.Message;
|
|||
|
|
break;
|
|||
|
|
case 50000:
|
|||
|
|
//自定义报错
|
|||
|
|
errMsg = CustomErrorFormatter(sqlException);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
errMsg = errMsg + "[ID]:" + id;
|
|||
|
|
throw new DomainException(errMsg);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
var tmsg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
|
|||
|
|
tmsg = tmsg + "[ID]:" + id;
|
|||
|
|
throw new DomainException(tmsg);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string GetProMsgVal(object data, string clomsMsg, PropertyInfo c)
|
|||
|
|
{
|
|||
|
|
var desc = c.GetAttribute<DescriptionAttribute>();
|
|||
|
|
if (desc != null)
|
|||
|
|
{
|
|||
|
|
clomsMsg += "[" + desc.Description + "]:" + c.GetValue(data) + ",";
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
clomsMsg += "[" + c.PropertyType.Name + "]:" + c.GetValue(data) + ",";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return clomsMsg;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//报错信息样例:Cannot insert duplicate key row in object 'dbo.TableName' with unique index 'IX_TableName_FieldName'. The duplicate key value is (XXX).
|
|||
|
|
private readonly Regex UniqueConstraintRegex_Table = new Regex(@"'dbo.(\w*)'", RegexOptions.Compiled);
|
|||
|
|
public string UniqueErrorFormatter(SqlException ex)
|
|||
|
|
{
|
|||
|
|
var message = ex.Errors[0]?.Message;
|
|||
|
|
//利用正则表达式匹配到表名
|
|||
|
|
var tableMatch = UniqueConstraintRegex_Table.Match(message);
|
|||
|
|
if (!tableMatch.Success)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
var tableName = tableMatch?.Groups[1]?.Value;
|
|||
|
|
//默认情况下,EF Core生成的唯一索引的命名是有规律的(如果是自定义的,也必须有规律),这样就用样可以通过正则表达式匹配到外键对应的字段
|
|||
|
|
Regex UniqueConstraintRegex = new Regex("'IX_" + tableName + @"_(\w*)'", RegexOptions.Compiled);
|
|||
|
|
var columnMatch = UniqueConstraintRegex.Match(message);
|
|||
|
|
if (!columnMatch.Success)
|
|||
|
|
{
|
|||
|
|
UniqueConstraintRegex = new Regex("'AK_" + tableName + @"_(\w*)'", RegexOptions.Compiled);
|
|||
|
|
columnMatch = UniqueConstraintRegex.Match(message);
|
|||
|
|
if (!columnMatch.Success)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
var columnName = columnMatch?.Groups[1]?.Value;
|
|||
|
|
//外键报错末尾是“The duplicate key value is (XXX).”,可以再次通过正则表达式匹配到重复数据
|
|||
|
|
var dupPart = "";
|
|||
|
|
var openingBadValue = message.IndexOf("(", StringComparison.Ordinal);
|
|||
|
|
if (openingBadValue > 0)
|
|||
|
|
{
|
|||
|
|
dupPart = message.Substring(openingBadValue + 1, message.Length - openingBadValue - 3);
|
|||
|
|
}
|
|||
|
|
//这样就解析出了报错信息,具体怎么组合就看需求了
|
|||
|
|
return "存在重复的键,字段:" + columnName + ",值:" + dupPart;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private readonly Regex ForeignKeyRegex_Table = new Regex(@"table ""dbo.(\w*)""", RegexOptions.Compiled);
|
|||
|
|
private readonly Regex ForeignKeyRegex_Column = new Regex(@"column '(\w*)'", RegexOptions.Compiled);
|
|||
|
|
//报错样例:The INSERT statement conflicted with the FOREIGN KEY constraint "FK_XXX". The conflict occurred in database "DBName", table "dbo.TableName", column 'ColumnName'.
|
|||
|
|
private readonly string Operation_Insert = "INSERT";
|
|||
|
|
private readonly string Operation_Merge = "MERGE";
|
|||
|
|
private readonly string Operation_Update = "UPDATE";
|
|||
|
|
private readonly string Operation_Delete = "DELETE";
|
|||
|
|
public string ForeignKeyErrorFormatter(SqlException ex)
|
|||
|
|
{
|
|||
|
|
var message = ex.Errors[0]?.Message;
|
|||
|
|
//利用规则匹配到操作:The {Operation} statement
|
|||
|
|
var operationName = message?.Substring(4, 6)?.Trim();
|
|||
|
|
//利用正则表达式匹配到表名
|
|||
|
|
var tableMatch = ForeignKeyRegex_Table.Match(message);
|
|||
|
|
if (!tableMatch.Success)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
var tableName = tableMatch?.Groups[1]?.Value;
|
|||
|
|
//增改涉及到的都是表自身,到这一步就结束了
|
|||
|
|
if (operationName == Operation_Merge || operationName == Operation_Insert)
|
|||
|
|
{
|
|||
|
|
return "新增数据时,外键约束报错:" + tableMatch;
|
|||
|
|
}
|
|||
|
|
if (operationName == Operation_Update)
|
|||
|
|
{
|
|||
|
|
return "更新数据时,外键约束报错:" + tableMatch;
|
|||
|
|
}
|
|||
|
|
//删除操作,涉及到的还有影响到的表
|
|||
|
|
var columnMatch = ForeignKeyRegex_Column.Match(message);
|
|||
|
|
if (!columnMatch.Success)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
var columnName = columnMatch?.Groups[1]?.Value;
|
|||
|
|
|
|||
|
|
Regex ForeignKeyRegex = new Regex($@"""FK_{tableName}_(\w*)_{columnName}""", RegexOptions.Compiled);
|
|||
|
|
var targetTableMatch = ForeignKeyRegex.Match(message);
|
|||
|
|
if (!targetTableMatch.Success)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
var targetTableName = targetTableMatch?.Groups[1]?.Value;
|
|||
|
|
|
|||
|
|
return "删除数据时,外键约束报错:表[" + targetTableName + "],字段:[" + columnName + "]";
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 自定义报错
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>格式化的自定义报错信息</returns>
|
|||
|
|
/// <param name="ex">SqlException</param>
|
|||
|
|
public string CustomErrorFormatter(SqlException ex)
|
|||
|
|
{
|
|||
|
|
var message = ex.Errors[0]?.Message;
|
|||
|
|
//这里根据自己定义的错误格式分别处理,比如说:Error:{ErrorMessage}
|
|||
|
|
var customErrorCode = message?.Split(":")?.First();
|
|||
|
|
return "自定义错误:" + customErrorCode;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void InitTreeData<T>(Guid orgId) where T : TreeEntityBase<T>, new()
|
|||
|
|
{
|
|||
|
|
List<T> updateEntites = new List<T>();
|
|||
|
|
|
|||
|
|
//var selectFields = new string[] { "ID", "IS_LEAF" };
|
|||
|
|
var data = this.GetEntities<T>(i => i.IS_LEAF && i.Nav_Children.Any(), null, true);
|
|||
|
|
if (data.Any())
|
|||
|
|
{
|
|||
|
|
data.ForEach(i => i.IS_LEAF = false);
|
|||
|
|
updateEntites.AddRange(data);
|
|||
|
|
}
|
|||
|
|
var leafData = this.GetEntities<T>(i => !i.IS_LEAF && !i.Nav_Children.Any(), null, true);
|
|||
|
|
if (leafData.Any())
|
|||
|
|
{
|
|||
|
|
leafData.ForEach(i => i.IS_LEAF = true);
|
|||
|
|
updateEntites.AddRange(leafData);
|
|||
|
|
}
|
|||
|
|
if (updateEntites.Any())
|
|||
|
|
this.UpdateEntities(updateEntites);
|
|||
|
|
}
|
|||
|
|
public async Task<int> ExecuteSqlCommandAsync(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters)
|
|||
|
|
{
|
|||
|
|
return await Database.ExecuteSqlRawAsync(sql, parameters);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
|||
|
|
{
|
|||
|
|
var entities = from e in ChangeTracker.Entries()
|
|||
|
|
where e.State == EntityState.Added
|
|||
|
|
|| e.State == EntityState.Modified
|
|||
|
|
select e.Entity;
|
|||
|
|
foreach (var entity in entities)
|
|||
|
|
{
|
|||
|
|
var validationContext = new ValidationContext(entity);
|
|||
|
|
|
|||
|
|
var dbExceptions = new List<ValidationException>();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
Validator.ValidateObject(entity, validationContext);
|
|||
|
|
}
|
|||
|
|
catch (ValidationException dbEx)
|
|||
|
|
{
|
|||
|
|
var errorBuilder = new StringBuilder();
|
|||
|
|
errorBuilder.AppendLine(dbEx.Message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (dbExceptions.Count > 0)
|
|||
|
|
{
|
|||
|
|
var errorBuilder = new StringBuilder();
|
|||
|
|
dbExceptions.ForEach(ve => errorBuilder.AppendLine(ve.Message));
|
|||
|
|
|
|||
|
|
throw new DomainException(errorBuilder.ToString());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int save = await base.SaveChangesAsync(cancellationToken);
|
|||
|
|
|
|||
|
|
return save;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void BeginTransaction()
|
|||
|
|
{
|
|||
|
|
this._TranscationLocker++;
|
|||
|
|
if (this._dbContextTransaction != null)
|
|||
|
|
return;
|
|||
|
|
this._dbContextTransaction = this.Database.BeginTransaction();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void CommitTransaction()
|
|||
|
|
{
|
|||
|
|
if (this._dbContextTransaction == null)
|
|||
|
|
return;
|
|||
|
|
this._TranscationLocker--;
|
|||
|
|
if (_TranscationLocker == 0)
|
|||
|
|
{
|
|||
|
|
this._dbContextTransaction.Commit();
|
|||
|
|
this._dbContextTransaction.Dispose();
|
|||
|
|
this._dbContextTransaction = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void RollbackTransaction()
|
|||
|
|
{
|
|||
|
|
if (this._dbContextTransaction == null)
|
|||
|
|
return;
|
|||
|
|
this._TranscationLocker = 0;
|
|||
|
|
this._dbContextTransaction.Rollback();
|
|||
|
|
this._dbContextTransaction.Dispose();
|
|||
|
|
this._dbContextTransaction = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public T AddEntity<T>(T entity) where T : class
|
|||
|
|
{
|
|||
|
|
if (entity == null) return null;
|
|||
|
|
return this.Add<T>(entity).Entity;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void AddEntities<T>(IEnumerable<T> entities) where T : class
|
|||
|
|
{
|
|||
|
|
if (entities == null || !entities.Any()) return;
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
this.AddRange(entities);
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public void UpdateEntity<T>(T entity) where T : class
|
|||
|
|
{
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
this.Update(entity);
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public void UpdateEntities<T>(IEnumerable<T> entities) where T : class
|
|||
|
|
{
|
|||
|
|
if (entities == null || !entities.Any()) return;
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
this.UpdateRange(entities);
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void UpdateEntities<T>(IEnumerable<T> entities, params string[] updateField) where T : class
|
|||
|
|
{
|
|||
|
|
if (entities == null || !entities.Any()) return;
|
|||
|
|
if (updateField == null || !updateField.Any())
|
|||
|
|
{
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
this.UpdateRange(entities);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
foreach (var i in entities)
|
|||
|
|
{
|
|||
|
|
var entitybase = this.Entry<T>(i);
|
|||
|
|
foreach (var prop in updateField)
|
|||
|
|
{
|
|||
|
|
//IsPrimitive=true .NET内置的类型
|
|||
|
|
if (prop != "ID")
|
|||
|
|
entitybase.Property(prop).IsModified = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void DeleteEntities<T>(IEnumerable<T> entities) where T : class
|
|||
|
|
{
|
|||
|
|
if (entities == null || !entities.Any()) return;
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
this.RemoveRange(entities);
|
|||
|
|
}
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
this.ChangeTracker.AutoDetectChangesEnabled = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public DataBaseType GetDataBaseType()
|
|||
|
|
{
|
|||
|
|
return this.DBType();
|
|||
|
|
}
|
|||
|
|
public T GetEntity<T>(Expression<Func<T, bool>> expression, string[] selectField, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return this.GetEntity<T>(expression, selectField, false, paths);
|
|||
|
|
}
|
|||
|
|
public T GetEntity<T>(Expression<Func<T, bool>> expression, string[] selectField, bool isTracking = true, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
//var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
Dictionary<string, DbOrder> order = new Dictionary<string, DbOrder>();
|
|||
|
|
order.TryAdd("ID", DbOrder.ASC);
|
|||
|
|
return this.GetEntity(expression, order, selectField, isTracking, paths);
|
|||
|
|
}
|
|||
|
|
public T GetEntity<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders, string[] selectField,
|
|||
|
|
bool isTracking = true, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
var linq = new Orderable<T>(queryTable);
|
|||
|
|
queryTable = linq.Queryable;
|
|||
|
|
bool isThen = false;
|
|||
|
|
if (orders == null)
|
|||
|
|
orders = new Dictionary<string, DbOrder>();
|
|||
|
|
if (!orders.Any())
|
|||
|
|
orders.TryAdd("ID", DbOrder.ASC);
|
|||
|
|
if (orders != null && orders.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var item in orders)
|
|||
|
|
{
|
|||
|
|
queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen);
|
|||
|
|
isThen = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (selectField != null && selectField.Any())
|
|||
|
|
queryTable = DynamicSelect(selectField, queryTable);
|
|||
|
|
return queryTable.FirstOrDefault();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public int GetCount<T>(Expression<Func<T, bool>> expression) where T : class
|
|||
|
|
{
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression);
|
|||
|
|
return queryTable.Count();
|
|||
|
|
}
|
|||
|
|
public IEnumerable<T> GetEntities<T>(Expression<Func<T, bool>> expression, string[] selectField, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return this.GetEntities<T>(expression, selectField, true, paths);
|
|||
|
|
}
|
|||
|
|
public IEnumerable<T> GetEntities<T>(Expression<Func<T, bool>> expression, string[] selectField, bool isTracking = true, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
if (selectField != null && selectField.Any())
|
|||
|
|
{
|
|||
|
|
queryTable = DynamicSelect(selectField, queryTable);
|
|||
|
|
}
|
|||
|
|
return queryTable.ToList();
|
|||
|
|
}
|
|||
|
|
public IEnumerable<T> GetOrderEntities<T>(Expression<Func<T, bool>> expression,
|
|||
|
|
Dictionary<string, DbOrder> orders, string[] selectField,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return this.GetOrderEntities<T>(expression, orders, null, selectField, true, paths);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public IEnumerable<T> GetOrderEntities<T>(Expression<Func<T, bool>> expression,
|
|||
|
|
Dictionary<string, DbOrder> orders, string[] selectField,
|
|||
|
|
bool isTracking = true, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return this.GetOrderEntities<T>(expression, orders, null, selectField, isTracking, paths);
|
|||
|
|
}
|
|||
|
|
public IEnumerable<T> GetOrderEntities<T>(Expression<Func<T, bool>> expression,
|
|||
|
|
Dictionary<string, DbOrder> orders, Action<IOrderable<T>> orderBy, string[] selectField,
|
|||
|
|
bool isTracking = true, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
var linq = new Orderable<T>(queryTable);
|
|||
|
|
if (orderBy != null)
|
|||
|
|
orderBy(linq);
|
|||
|
|
queryTable = linq.Queryable;
|
|||
|
|
bool isThen = false;
|
|||
|
|
if (orders != null && orders.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var item in orders)
|
|||
|
|
{
|
|||
|
|
queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen);
|
|||
|
|
isThen = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (selectField != null && selectField.Any())
|
|||
|
|
queryTable = DynamicSelect(selectField, queryTable);
|
|||
|
|
return queryTable.ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public PagedResultDto<T> GetOrderPageEntities<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders, string[] selectField,
|
|||
|
|
int pageSize, int startIndex,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return this.GetOrderPageEntities(expression, orders, selectField, pageSize, startIndex, true, paths);
|
|||
|
|
}
|
|||
|
|
public PagedResultDto<T> GetOrderPageEntities<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders, string[] selectField,
|
|||
|
|
int pageSize, int startIndex, bool isTracking = true,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return this.GetOrderPageEntities(expression, orders, selectField, pageSize, startIndex, null, isTracking, paths);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public PagedResultDto<T> GetOrderPageEntities<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders,
|
|||
|
|
int pageSize, int startIndex, Action<IOrderable<T>> orderBy, bool isTracking = true,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
if (pageSize == 0) throw new Exception("请设置PageSize");
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
var linq = new Orderable<T>(queryTable);
|
|||
|
|
if (orderBy != null)
|
|||
|
|
orderBy(linq);
|
|||
|
|
queryTable = linq.Queryable;
|
|||
|
|
bool isThen = false;
|
|||
|
|
if (orders != null && orders.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var item in orders)
|
|||
|
|
{
|
|||
|
|
queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen);
|
|||
|
|
isThen = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var result = new PagedResultDto<T>();
|
|||
|
|
result.TotalCount = queryTable.Count();
|
|||
|
|
|
|||
|
|
result.Items = queryTable.Skip(startIndex)
|
|||
|
|
.Take(pageSize)
|
|||
|
|
.ToArray();
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public PagedResultDto<T> GetOrderPageEntities<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders, string[] selectField,
|
|||
|
|
int pageSize, int startIndex, Action<IOrderable<T>> orderBy, bool isTracking = true,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
if (pageSize == 0) throw new Exception("请设置PageSize");
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
var linq = new Orderable<T>(queryTable);
|
|||
|
|
if (orderBy != null)
|
|||
|
|
orderBy(linq);
|
|||
|
|
queryTable = linq.Queryable;
|
|||
|
|
bool isThen = false;
|
|||
|
|
if (orders != null && orders.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var item in orders)
|
|||
|
|
{
|
|||
|
|
queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen);
|
|||
|
|
isThen = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (selectField != null && selectField.Any())
|
|||
|
|
queryTable = DynamicSelect(selectField, queryTable);
|
|||
|
|
|
|||
|
|
|
|||
|
|
var result = new PagedResultDto<T>();
|
|||
|
|
result.TotalCount = queryTable.Count();
|
|||
|
|
|
|||
|
|
result.Items = queryTable.Skip(startIndex)
|
|||
|
|
.Take(pageSize)
|
|||
|
|
.ToArray();
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
//
|
|||
|
|
public async Task<PagedResultDto<T>> GetOrderPageEntitiesSync<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders,
|
|||
|
|
int pageSize, int startIndex,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return await this.GetOrderPageEntitiesSync(expression, orders, pageSize, startIndex, true, paths);
|
|||
|
|
}
|
|||
|
|
public async Task<PagedResultDto<T>> GetOrderPageEntitiesSync<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders,
|
|||
|
|
int pageSize, int startIndex, bool isTracking = true,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
return await this.GetOrderPageEntitiesSync(expression, orders, pageSize, startIndex, null, isTracking, paths);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public async Task<PagedResultDto<T>> GetOrderPageEntitiesSync<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders,
|
|||
|
|
int pageSize, int startIndex, Action<IOrderable<T>> orderBy, bool isTracking = true,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
if (pageSize == 0) throw new Exception("请设置PageSize");
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
var linq = new Orderable<T>(queryTable);
|
|||
|
|
if (orderBy != null)
|
|||
|
|
orderBy(linq);
|
|||
|
|
queryTable = linq.Queryable;
|
|||
|
|
bool isThen = false;
|
|||
|
|
if (orders != null && orders.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var item in orders)
|
|||
|
|
{
|
|||
|
|
queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen);
|
|||
|
|
isThen = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var result = new PagedResultDto<T>();
|
|||
|
|
result.TotalCount = await queryTable.CountAsync();
|
|||
|
|
|
|||
|
|
result.Items = await queryTable.Skip(startIndex)
|
|||
|
|
.Take(pageSize)
|
|||
|
|
.ToArrayAsync();
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
public PagedResultDto<T> GetPageEntities<T>(Expression<Func<T, bool>> expression, Dictionary<string, DbOrder> orders, string[] selectField,
|
|||
|
|
int pageSize, int startIndex, Action<IOrderable<T>> orderBy, bool isTracking = true,
|
|||
|
|
params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
if (pageSize == 0) throw new Exception("请设置PageSize");
|
|||
|
|
var queryTable = this.DoGetQuerTable<T>(expression, isTracking, paths);
|
|||
|
|
var linq = new Orderable<T>(queryTable);
|
|||
|
|
if (orderBy != null)
|
|||
|
|
orderBy(linq);
|
|||
|
|
queryTable = linq.Queryable;
|
|||
|
|
|
|||
|
|
var result = new PagedResultDto<T>();
|
|||
|
|
result.TotalCount = queryTable.Count();
|
|||
|
|
result.Items = queryTable.Skip(startIndex)
|
|||
|
|
.Take(pageSize)
|
|||
|
|
.ToArray();
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private IQueryable<T> DynamicSelect<T>(string[] selectField, IQueryable<T> queryTable)
|
|||
|
|
{
|
|||
|
|
if (!selectField.Contains("ORG_ID"))
|
|||
|
|
selectField = selectField.Append("ORG_ID").ToArray();
|
|||
|
|
var selectSql = "New(";
|
|||
|
|
if (selectField != null && selectField.Any())
|
|||
|
|
{
|
|||
|
|
var type = typeof(T);
|
|||
|
|
foreach (var s in selectField)
|
|||
|
|
{
|
|||
|
|
if (s.Contains(".") || type.GetProperty(s) == null)
|
|||
|
|
continue;
|
|||
|
|
selectSql += s + ",";
|
|||
|
|
}
|
|||
|
|
selectSql = selectSql.Trim(',');
|
|||
|
|
selectSql += ")";
|
|||
|
|
queryTable = queryTable.Select<T>(selectSql);
|
|||
|
|
}
|
|||
|
|
return queryTable;
|
|||
|
|
}
|
|||
|
|
private IQueryable<T> DoGetQuerTable<T>(Expression<Func<T, bool>> expression, bool isTracking = true, params string[] paths) where T : class
|
|||
|
|
{
|
|||
|
|
var queryTable = this.Set<T>().AsQueryable();
|
|||
|
|
if (expression != null)
|
|||
|
|
queryTable = queryTable.Where(expression);
|
|||
|
|
if (paths != null && paths.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var item in paths)
|
|||
|
|
queryTable = queryTable.Include(item);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!isTracking)
|
|||
|
|
queryTable = queryTable.AsNoTracking();
|
|||
|
|
return queryTable;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region redis
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
private string GetRedisPropertyValue<T>(T entity, string name)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var properties = entity.GetType().GetProperties();
|
|||
|
|
|
|||
|
|
var property = properties.FirstOrDefault(o => o.Name == name);
|
|||
|
|
if (property != null)
|
|||
|
|
{
|
|||
|
|
return property.GetValue(entity, null).ToString();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return string.Empty;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
return string.Empty;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region methods
|
|||
|
|
|
|||
|
|
|
|||
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|||
|
|
{
|
|||
|
|
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
|||
|
|
{
|
|||
|
|
entityType.SetTableName(entityType.DisplayName());
|
|||
|
|
entityType.GetForeignKeys()
|
|||
|
|
.Where(fk => fk.DeleteBehavior == DeleteBehavior.Cascade)
|
|||
|
|
.ToList()
|
|||
|
|
.ForEach(fk => fk.DeleteBehavior = DeleteBehavior.Restrict);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
foreach (var property in modelBuilder.Model.GetEntityTypes()
|
|||
|
|
.SelectMany(t => t.GetProperties())
|
|||
|
|
.Where(p => p.ClrType == typeof(decimal)))
|
|||
|
|
{
|
|||
|
|
property.SetColumnType("decimal(18, 6)");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
var files = Directory.GetFiles(System.AppContext.BaseDirectory, "*.Data.dll").ToList();
|
|||
|
|
var BaseFiles = Directory.GetFiles(System.AppContext.BaseDirectory, "*APT.Infrastructure.EF.dll").ToList();
|
|||
|
|
files.AddRange(BaseFiles);
|
|||
|
|
if (files.Count > 0)
|
|||
|
|
{
|
|||
|
|
foreach (var file in files)
|
|||
|
|
{
|
|||
|
|
var assembly = Assembly.LoadFrom(file);
|
|||
|
|
if (assembly != null)
|
|||
|
|
{
|
|||
|
|
modelBuilder.ApplyConfigurationsFromAssembly(assembly);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
base.OnModelCreating(modelBuilder);
|
|||
|
|
this.GetEfModelByModel(modelBuilder.Model);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void GetEfModelByModel(IModel model)
|
|||
|
|
{
|
|||
|
|
_efModel = new EFModel();
|
|||
|
|
foreach (var entity in model.GetEntityTypes())
|
|||
|
|
{
|
|||
|
|
EFModelTable efTable = new EFModelTable();
|
|||
|
|
efTable.Name = entity.ClrType.Name;
|
|||
|
|
|
|||
|
|
var properties = entity.GetProperties().ToList();
|
|||
|
|
foreach (var property in properties)
|
|||
|
|
{
|
|||
|
|
EFModelField field = new EFModelField();
|
|||
|
|
field.FieldType = property.ClrType.GetUnNullableType();
|
|||
|
|
field.IsNull = property.IsNullable;
|
|||
|
|
field.Name = property.Name;
|
|||
|
|
field.TypeName = field.FieldType.Name;
|
|||
|
|
field.PropertyInfo = property.PropertyInfo;
|
|||
|
|
efTable.Fields.Add(field);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var foreignKeys = entity.GetForeignKeys().ToList();
|
|||
|
|
foreach (var fKey in foreignKeys)
|
|||
|
|
{
|
|||
|
|
EFModelForeignKey foreignKey = CreateEFModelForeignKey(fKey);
|
|||
|
|
if (foreignKey == null) continue;
|
|||
|
|
efTable.ForeignKeys.Add(foreignKey);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var navigations = entity.GetNavigations().ToList();
|
|||
|
|
foreach (var nav in navigations)
|
|||
|
|
{
|
|||
|
|
if (nav.ForeignKey == null) continue;
|
|||
|
|
EFModelForeignKey foreignKey = CreateEFModelForeignKey(nav.ForeignKey);
|
|||
|
|
if (foreignKey == null) continue;
|
|||
|
|
efTable.AllForeignKeys.Add(foreignKey);
|
|||
|
|
}
|
|||
|
|
_efModel.Tables.Add(efTable);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private EFModelForeignKey CreateEFModelForeignKey(IForeignKey fKey)
|
|||
|
|
{
|
|||
|
|
if (!fKey.Properties.Any() ||
|
|||
|
|
fKey.DependentToPrincipal == null && fKey.PrincipalToDependent == null)
|
|||
|
|
return null;
|
|||
|
|
EFModelForeignKey foreignKey = new EFModelForeignKey();
|
|||
|
|
foreignKey.ForeignFieldName = fKey.Properties[0].Name;
|
|||
|
|
foreignKey.IsNull = fKey.Properties[0].IsNullable;
|
|||
|
|
if (fKey.DependentToPrincipal != null)
|
|||
|
|
{
|
|||
|
|
foreignKey.ForeignNavName = fKey.DependentToPrincipal.Name;
|
|||
|
|
foreignKey.ForeignTableName = fKey.DependentToPrincipal.PropertyInfo.PropertyType.Name;
|
|||
|
|
}
|
|||
|
|
if (fKey.PrincipalToDependent != null)
|
|||
|
|
foreignKey.MasterNavName = fKey.PrincipalToDependent.Name;
|
|||
|
|
foreignKey.ForeignKey = fKey;
|
|||
|
|
return foreignKey;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
var isSqlLog = LibUtils.ToBoolean(ConfigurationManager.AppSettings["isSqlLog"]);
|
|||
|
|
|
|||
|
|
var logFactory = ServiceLocator.Instance.GetService<ILoggerFactory>();
|
|||
|
|
var logProvider = ServiceLocator.Instance.GetService<ILoggerProvider>();
|
|||
|
|
if (isSqlLog && logFactory != null && logProvider != null)
|
|||
|
|
{
|
|||
|
|
//logFactory.AddProvider(logProvider);
|
|||
|
|
optionsBuilder.EnableSensitiveDataLogging().UseLoggerFactory(logFactory);
|
|||
|
|
}
|
|||
|
|
//optionsBuilder.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrWhiteSpace(namedConnection))
|
|||
|
|
{
|
|||
|
|
var dbType = this.DBType();
|
|||
|
|
if (dbType == DataBaseType.Oracle)
|
|||
|
|
{
|
|||
|
|
//optionsBuilder
|
|||
|
|
// .UseLazyLoadingProxies(false)
|
|||
|
|
// .UseOracle(this.ConnectionString);
|
|||
|
|
}
|
|||
|
|
else if (dbType == DataBaseType.MySQL)
|
|||
|
|
{
|
|||
|
|
//optionsBuilder
|
|||
|
|
// .UseLazyLoadingProxies(false)
|
|||
|
|
// .UseMySQL(this.ConnectionString);
|
|||
|
|
}
|
|||
|
|
else if (dbType == DataBaseType.Postgresql)
|
|||
|
|
{
|
|||
|
|
//optionsBuilder
|
|||
|
|
// .UseLazyLoadingProxies(false)
|
|||
|
|
// .UseNpgsql(this.ConnectionString);
|
|||
|
|
}
|
|||
|
|
else if (dbType == DataBaseType.SQL)
|
|||
|
|
{
|
|||
|
|
optionsBuilder
|
|||
|
|
.UseLazyLoadingProxies(false)
|
|||
|
|
.UseSqlServer(this.ConnectionString);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 根据表名获取表数据结构
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="tableName"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public EFModelTable GetModelTable(string tableName)
|
|||
|
|
{
|
|||
|
|
//if (_efModel == null)
|
|||
|
|
// this.GetEntity<T_FM_ORGANIZATION>(t => t.CODE == "0000", null);
|
|||
|
|
if (_efModel == null && this.Model != null)
|
|||
|
|
this.GetEfModelByModel(this.Model);
|
|||
|
|
if (_efModel == null || _efModel.Tables == null || string.IsNullOrEmpty(tableName)) return null;
|
|||
|
|
return _efModel.Tables.FirstOrDefault(t => string.Compare(t.Name, tableName, true) == 0);
|
|||
|
|
}
|
|||
|
|
public List<EFModelForeignKey> GetModelForeignKey(string tableName)
|
|||
|
|
{
|
|||
|
|
var table = this.GetModelTable(tableName);
|
|||
|
|
if (table == null) return null;
|
|||
|
|
var fkey = table.ForeignKeys;
|
|||
|
|
return fkey;
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 根据表名、字段名称获取字段结构
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="tableName"></param>
|
|||
|
|
/// <param name="fieldName"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public EFModelField GetModelField(string tableName, string fieldName)
|
|||
|
|
{
|
|||
|
|
var table = this.GetModelTable(tableName);
|
|||
|
|
if (table == null) return null;
|
|||
|
|
return table.Fields.FirstOrDefault(t => string.Compare(t.Name, fieldName, true) == 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 根据表名,导航名称获取外键信息
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="tableName"></param>
|
|||
|
|
/// <param name="navName"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public EFModelForeignKey GetModelForeignKey(string tableName, string navName)
|
|||
|
|
{
|
|||
|
|
var table = this.GetModelTable(tableName);
|
|||
|
|
if (table == null) return null;
|
|||
|
|
var fkey = table.ForeignKeys.FirstOrDefault(t => string.Compare(t.ForeignNavName, navName, true) == 0);
|
|||
|
|
if (fkey == null)
|
|||
|
|
{
|
|||
|
|
fkey = table.AllForeignKeys.FirstOrDefault(t => string.Compare(t.MasterNavName, navName, true) == 0);
|
|||
|
|
}
|
|||
|
|
return fkey;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 根据表名,ID字段名称获取外键信息
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="tableName"></param>
|
|||
|
|
/// <param name="idFieldName"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public EFModelForeignKey GetModelForeignKeyById(string tableName, string idFieldName)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
var table = this.GetModelTable(tableName);
|
|||
|
|
if (table == null) return null;
|
|||
|
|
return table.ForeignKeys.FirstOrDefault(t => string.Compare(t.ForeignFieldName, idFieldName, true) == 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
private List<T> RawSqlQuery<T>(string query, Func<DbDataReader, T> map)
|
|||
|
|
{
|
|||
|
|
using (var command = this.Database.GetDbConnection().CreateCommand())
|
|||
|
|
{
|
|||
|
|
command.CommandText = query;
|
|||
|
|
command.CommandType = CommandType.Text;
|
|||
|
|
|
|||
|
|
this.Database.OpenConnection();
|
|||
|
|
|
|||
|
|
using (var result = command.ExecuteReader())
|
|||
|
|
{
|
|||
|
|
var entities = new List<T>();
|
|||
|
|
|
|||
|
|
while (result.Read())
|
|||
|
|
{
|
|||
|
|
entities.Add(map(result));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return entities;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|