using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using IRaCIS.Core.Domain.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using AutoMapper.QueryableExtensions;
using EFCore.BulkExtensions;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.Data.SqlClient;
using Newtonsoft.Json;

namespace IRaCIS.Core.Infra.EFCore
{
    public class Repository<TEntity> : IRepository<TEntity>
        where TEntity : Entity, new()
    {

        public IMapper _mapper { get; set; }
        public IRaCISDBContext _dbContext { get; set; }

        public DbSet<TEntity> _dbSet => _dbContext.Set<TEntity>();

        public IUserInfo _userInfo { get; set; }

        public Repository(IRaCISDBContext dbContext, IMapper mapper, IUserInfo userInfo)
        {
            _dbContext = dbContext;
            _mapper = mapper;
            _userInfo = userInfo;

        }

        #region 异步部分



        public async Task<TEntity> InsertOrUpdateAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
        {
            var entity = _mapper.Map<TEntity>(from);

            if (entity.Id == Guid.Empty)
            {
                return await InsertFromDTOAsync(from, autoSave, verify);
            }
            else
            {
                return await UpdateFromDTOAsync(from, autoSave, false, verify);
            }
        }


        private async Task EntityVerifyAsync(bool isAdd, EntityVerifyExp<TEntity>[] verify, Guid? entitydId = null)
        {

            if (isAdd)
            {
                foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify))
                {
                    if (await _dbSet.IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
                    {
                        throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
                    }
                }
            }
            else
            {
                foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify))
                {
                    if (verifyItem.verifyType == VerifyEnum.OnlyUpdate)
                    {
                        if (await _dbSet.IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
                        {
                            throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
                        }
                    }
                    else if (verifyItem.verifyType == VerifyEnum.Both)
                    {
                        if (await _dbSet.IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp.And(t => t.Id != entitydId)).ConfigureAwait(false))
                        {
                            throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
                        }
                    }
                }
            }

        }

        public async Task<TEntity> InsertFromDTOAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
        {
            List<DataInspection> datas = new List<DataInspection>();
            var entity = _mapper.Map<TEntity>(from);

            await EntityVerifyAsync(true, verify);

            await _dbSet.AddAsync(entity).ConfigureAwait(false);

            await SaveChangesAsync(autoSave);

            // 这里用不了 switch
            //switch (typeof(TEntity))
            //{
            //    case typeof(Dictionary):
            //        break;
            //}

            var createtime = DateTime.Now.AddSeconds(1);

            // 受试者
            if (typeof(TEntity) == typeof(Subject))
            {
                Subject data = entity as Subject;
                datas.Add(new DataInspection()
                {
                    TrialId = data.TrialId,
                    SiteId = data.SiteId,
                    SubjectId = data.Id,
                    SubjectCode = data.Code,
                    IsSign = false,
                    CreateTime = createtime,
                    Identification = "Init|Subject|Status|Subject",
                    JsonDetail = JsonConvert.SerializeObject(new
                    {
                        Status = "新增",
                    })
                });
            }
            await AddListInspectionRecordAsync(datas);
            return entity;

        }


        #region 稽查
        /// <summary>
        /// 添加稽查记录
        /// </summary>
        /// <param name="datas"></param>
        /// <returns></returns>
        public async Task AddListInspectionRecordAsync(List<DataInspection> datas)
        {
            //var trialIds= datas.Select(x=>x.TrialId).Distinct().ToList();
            //var subjectVisitIds= datas.Select(x=>x.SubjectVisitId).Distinct().ToList();
            //var subjectIds = datas.Select(x => x.SubjectId).Distinct().ToList();
            //var siteIds = datas.Select(x => x.SiteId).Distinct().ToList();
            //var childrenTypes= datas.Select(x => x.ChildrenType).Distinct().ToList();
            //var objectTypes = datas.Select(x => x.ObjectType).Distinct().ToList();

            foreach (var add in datas)
            {
                await SetInspectionNameValue(add);
                add.ParentId = (await _dbContext.DataInspection.AsQueryable().Where(x => x.TrialId == add.TrialId && x.SubjectVisitId == add.SubjectVisitId && x.SubjectId == add.SubjectId && x.SiteId == add.SiteId && x.ChildrenType == add.ChildrenType && x.ObjectType == add.ObjectType && x.VisitStageId == add.VisitStageId && x.GeneralId == add.GeneralId).OrderByDescending(x => x.CreateTime).FirstOrDefaultAsync())?.Id;
                add.CreateUserId = _userInfo.Id;
                add.IP = _userInfo.IP;
                var JsonData = JsonConvert.DeserializeObject<IDictionary<string, object>>(add.JsonDetail);

                foreach (var item in JsonData.Keys)
                {
                    if (JsonData[item] == null)
                    {
                        continue;
                    }
                    if (JsonData[item].ToString().ToLower() == "true".ToLower())
                    {
                        JsonData[item] = "是";
                    }
                    else if (JsonData[item].ToString().ToLower() == "false".ToLower())
                    {
                        JsonData[item] = "否";
                    }
                }
                if (add.CreateTime == default(DateTime))
                {
                    add.CreateTime = DateTime.Now;
                }
                add.JsonDetail = JsonConvert.SerializeObject(JsonData);
            }

            await _dbContext.DataInspection.AddRangeAsync(datas);
            await _dbContext.SaveChangesAsync();

        }

        /// <summary>
        /// IsNullOrEmpty
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private bool IsNullOrEmpty(object value)
        {
            if (value == null || value.ToString() == string.Empty)
            {
                return true;
            }
            else
            {
                return false;
            }
        }



        /// <summary>
        /// 设置项目以及名称
        /// </summary>
        /// <param name="Data"></param>
        /// <returns></returns>
        public async Task SetInspectionNameValue(DataInspection Data)
        {
            #region 项目名称

            var trialdata = await _dbContext.Trial.FirstOrDefaultAsync(x => x.Id == Data.TrialId);
            Data.ResearchProgramNo = trialdata?.ResearchProgramNo;
            if (IsNullOrEmpty(Data.TrialName))
            {
                Data.TrialName = trialdata?.ExperimentName;
            }
            #endregion

            #region 测试中心名称


            Data.SiteCode = (await _dbContext.TrialSite.IgnoreQueryFilters().FirstOrDefaultAsync(x => x.TrialId == Data.TrialId && x.SiteId == Data.SiteId))?.TrialSiteCode;

            var sitedata = await _dbContext.Site.FirstOrDefaultAsync(x => x.Id == Data.SiteId);

            if (IsNullOrEmpty(Data.SiteName))
            {
                Data.SiteName = sitedata?.SiteName;
            }
            #endregion

            #region 受试者


            if (IsNullOrEmpty(Data.SubjectCode))
            {

                Data.SubjectCode = (await _dbContext.Subject.FirstOrDefaultAsync(x => x.Id == Data.SubjectId))?.Code;
            }
            #endregion

            #region 访视
            if (IsNullOrEmpty(Data.SubjectVisitName))
            {
                Data.SubjectVisitName = (await _dbContext.SubjectVisit.FirstOrDefaultAsync(x => x.Id == Data.SubjectVisitId))?.VisitName;
            }
            #endregion

            #region 创建者
            if (IsNullOrEmpty(Data.CreateUserName) || IsNullOrEmpty(Data.RoleName))
            {
                var userdata = await _dbContext.Users.AsQueryable().Where(x => x.Id == Data.CreateUserId).GroupJoin(_dbContext.UserType.AsQueryable(), a => a.UserTypeId, b => b.Id, (a, b) => new
                {
                    UserName = a.FirstName + a.LastName,
                    Role = b
                }).SelectMany(a => a.Role, (m, n) => new
                {
                    UserName = m.UserName,
                    RoleName = n.UserTypeShortName
                }).FirstOrDefaultAsync();

                if (userdata != null)
                {
                    if (IsNullOrEmpty(Data.CreateUserName))
                    {
                        Data.CreateUserName = userdata?.UserName;
                    }


                    if (IsNullOrEmpty(Data.RoleName))
                    {
                        Data.RoleName = userdata?.RoleName;
                    }
                }
            }
            #endregion

            #region 取操作类型
            try
            {
                var from = await _dbContext.FrontAuditConfig.FirstOrDefaultAsync(x => x.Identification == Data.Identification);
                Data.ObjectType = from.ObjectTypeId;
                Data.OptType = from.OptTypeId;
                Data.ChildrenType = from.ChildrenTypeId;
                Data.ModuleType = from.ModuleTypeId;
            }
            catch (Exception)
            {

                throw new BusinessValidationFailedException("操作标识异常");
            }


            #endregion

        }
        #endregion

        /// <summary>
        /// 用前端传递的视图模型字段,更新,同时返回数据库该条记录的原始信息,方便对比某些字段是否更改,进行相应的逻辑操作
        /// </summary>
        /// <typeparam name="TFrom"></typeparam>
        /// <param name="from"></param>
        /// <param name="autoSave"></param>
        /// <param name="ignoreDtoNullProperty"></param>
        /// <param name="verify"></param>
        /// <returns></returns>
        /// <exception cref="BusinessValidationFailedException"></exception>
        public async Task<TEntity> UpdateFromDTOAsync<TFrom>(TFrom from, bool autoSave = false, bool ignoreDtoNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
        {

            var entity = _mapper.Map<TEntity>(from);

            await EntityVerifyAsync(false, verify, entity.Id);

            var dbEntity = await _dbSet.IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == entity.Id).ConfigureAwait(false);

            if (dbEntity == null)
            {
                throw new BusinessValidationFailedException(
                    " Update object not exist in db,Please check if the parameter Id is passed incorrectly");
            }

            var dbBeforEntity = dbEntity.Clone();


            _mapper.Map(from, dbEntity);


            //DTO  null  属性不更新  防止意外操作,导致保存数据错误,或者 add 和update 用一个模型,更新的时候,只传递了部分字段,导致,不想更新的字段,因为没传递值,用null覆盖了
            // Guid?属性 为null 时   映射到  Guid 时  默认会变成  Guid.Empty   
            if (ignoreDtoNullProperty)
            {
                var dbEntityProp = typeof(TEntity).GetProperties();
                foreach (var propertyInfo in from.GetType().GetProperties())
                {
                    if (propertyInfo.GetValue(from) == null && dbEntityProp.Any(t => t.Name == propertyInfo.Name))
                    {
                        _dbContext.Entry(dbEntity).Property(propertyInfo.Name).IsModified = false;
                    }
                }
            }

            await SaveChangesAsync(autoSave);


            return dbBeforEntity;
        }


        private async Task<bool> SaveChangesAsync(bool autoSave)
        {
            if (autoSave)
            {
                return await SaveChangesAsync();
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 通过主键id  和表达式树 更新部分字段  例如  Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584"),u => new Dictionary() { ParentId = null, Code = "test" }  默认会去处理更新更新人 更新时间
        /// </summary>
        /// <param name="id"></param>
        /// <param name="updateFactory"></param>
        /// <param name="autoSave"></param>
        /// <param name="verify"></param>
        /// <returns></returns>
        public async Task UpdatePartialFields(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
        {
            await SetPartialFieldUpdateAsync(id, updateFactory, verify);

            await SaveChangesAsync(autoSave);

        }

        public async Task<bool> UpdatePartialFieldsNow(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
            params EntityVerifyExp<TEntity>[] verify)
        {
            await SetPartialFieldUpdateAsync(id, updateFactory, verify);
            return await SaveChangesAsync(true);
        }

        private async Task SetPartialFieldUpdateAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, params EntityVerifyExp<TEntity>[] verify)
        {
            await EntityVerifyAsync(false, verify, id);

            var entity = new TEntity() { Id = id };

            var entityEntry = _dbContext.Entry(entity);

            entityEntry.State = EntityState.Detached;


            List<PropertyInfo> list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name)
                .Select(propName => typeof(TEntity).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList();

            Func<TEntity, TEntity> func = updateFactory.Compile();

            TEntity applyObj = func(entity);

            foreach (PropertyInfo prop in list)
            {
                object value = prop.GetValue((object)applyObj);
                prop.SetValue((object)entity, value);

                _dbContext.Entry(entity).Property(prop.Name).IsModified = true;
            }

            #region Test


            //updateFactory.Compile()(entity);

            //List<string> propNameList = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name).ToList();

            //foreach (string propName in propNameList)
            //{
            //    _dbContext.Entry(entity).Property(propName).IsModified = true;
            //}

            #endregion
        }


        /// <summary>
        /// 部分字段更新  (只更新传递的字段名 new[] {nameof(User.Name), nameof(User.Age))
        /// new Dictionary() { ParentId = null, Code = "test",Id=Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584")},new[] {nameof(Dictionary.Name), nameof(Dictionary.Age))
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="propertyNames"> 更新的字段数组 </param>
        /// <param name="autoSave"></param>
        /// <param name="ignoreEntityNullProperty"></param>
        /// <param name="verify"></param>
        /// <returns></returns>
        public async Task<TEntity> UpdatePartialFields(TEntity entity, string[] propertyNames,
            bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
        {
            await EntityVerifyAsync(false, verify, entity.Id);

            var entityEntry = _dbContext.Entry(entity);
            entityEntry.State = EntityState.Detached;


            foreach (var propertyName in propertyNames)
            {
                _dbContext.Entry(entity).Property(propertyName).IsModified = true;
            }

            // 忽略空值
            IgnoreNullValues(ref entity, ignoreEntityNullProperty);

            return entityEntry.Entity;
        }

        /// <summary>
        /// 更新  排除某些字段的更新  排除方式: new[] {nameof(User.Name), nameof(User.Age)
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="propertyNames"></param>
        /// <param name="autoSave"></param>
        /// <param name="ignoreEntityNullProperty"></param>
        /// <param name="verify"></param>
        /// <returns></returns>
        public async Task<TEntity> UpdateExcludeFields(TEntity entity, string[] propertyNames, bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
        {

            await EntityVerifyAsync(false, verify, entity.Id);

            var entityEntry = _dbContext.Entry(entity);
            entityEntry.State = EntityState.Modified;


            foreach (var propertyName in propertyNames)
            {
                _dbContext.Entry(entity).Property(propertyName).IsModified = false;
            }

            // 忽略空值
            IgnoreNullValues(ref entity, ignoreEntityNullProperty);

            return entityEntry.Entity;
        }

        /// <summary>
        /// 忽略空值属性
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="ignoreNullValues"></param>
        private void IgnoreNullValues(ref TEntity entity, bool? ignoreNullValues = null)
        {
            var isIgnore = ignoreNullValues;
            if (isIgnore == false) return;

            // 获取所有的属性
            var properties = _dbSet.EntityType.GetProperties();
            if (properties == null) return;

            foreach (var propety in properties)
            {
                var entityProperty = _dbContext.Entry(entity).Property(propety.Name);
                var propertyValue = entityProperty?.CurrentValue;
                var propertyType = entityProperty?.Metadata?.PropertyInfo?.PropertyType;

                // 判断是否是无效的值,比如为 null,默认时间,以及空 Guid 值
                var isInvalid = propertyValue == null
                                || (propertyType == typeof(DateTime) && propertyValue?.ToString() == new DateTime().ToString())
                                || (propertyType == typeof(DateTimeOffset) && propertyValue?.ToString() == new DateTimeOffset().ToString())
                                || (propertyType == typeof(Guid) && propertyValue?.ToString() == Guid.Empty.ToString());

                if (isInvalid && entityProperty != null)
                {
                    entityProperty.IsModified = false;
                }
            }
        }


        public async Task<bool> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            return await _dbContext.SaveChangesAsync(cancellationToken) > 0;
        }

        public async ValueTask<TEntity> FindAsync(Guid id, CancellationToken cancellationToken = default)
        {
            return await _dbContext.FindAsync<TEntity>(id);
        }

        //有可能是联合主键,本项目没用到,用Guid
        public async ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
        {
            return await _dbContext.FindAsync<TEntity>(keyValues);
        }

        public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> exp = null, bool ignoreQueryFilters = false)
        {

            var query = _dbSet.AsQueryable();

            if (ignoreQueryFilters)
            {
                query = query.IgnoreQueryFilters();
            }
            if (exp == null)
                return await query.FirstOrDefaultAsync().ConfigureAwait(false);
            return await query.FirstOrDefaultAsync(exp).ConfigureAwait(false);
        }

        public async ValueTask<TEntity> AddAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {

            await _dbSet.AddAsync(entity).ConfigureAwait(false);

            if (autoSave)
            {
                await SaveChangesAsync(cancellationToken);
            }

            return entity;
        }


        public async Task<IEnumerable<TEntity>> AddRangeAsync(IEnumerable<TEntity> entities)
        {
            await _dbSet.AddRangeAsync(entities).ConfigureAwait(false);

            return entities;
        }


        public async Task<bool> AddRangeAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await _dbSet.AddRangeAsync(entities).ConfigureAwait(false);

            if (autoSave)
            {
                return await SaveChangesAsync(cancellationToken);
            }
            else
            {
                return false;
            }
        }





        public async Task<TResult> MaxAsync<TResult>(Expression<Func<TEntity, TResult>> selector)
        {

            return await _dbSet.AsNoTracking().MaxAsync(selector);
        }

        public async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> exp, bool ignoreQueryFilters = false)
        {
            var query = _dbSet.AsQueryable();

            if (ignoreQueryFilters)
            {
                query = query.IgnoreQueryFilters();
            }

            return await query.AsNoTracking().AnyAsync(exp);
        }

        public async Task<int> CountAsync(Expression<Func<TEntity, bool>> whereLambda = null, bool ignoreQueryFilters = false)
        {
            var query = _dbSet.AsQueryable();

            if (ignoreQueryFilters)
            {
                query = query.IgnoreQueryFilters();
            }

            return whereLambda == null ? await query.AsNoTracking().CountAsync() : await query.AsNoTracking().CountAsync(whereLambda);
        }


        public async Task<bool> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _dbSet.Update(entity);

            if (autoSave)
            {
                return await SaveChangesAsync(cancellationToken);
            }
            else
            {
                return false;
            }
        }



        public async Task<bool> DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _dbSet.Remove(entity);

            //var entry = _dbSet.Attach(entity);
            //entry.State = EntityState.Deleted;

            if (autoSave)
            {
                return await SaveChangesAsync(cancellationToken);
            }
            else
            {
                return false;
            }
        }



        public async Task<bool> BatchDeleteAsync(Expression<Func<TEntity, bool>> deleteFilter)
        {
            return await _dbSet.IgnoreQueryFilters().Where(deleteFilter).BatchDeleteAsync() > 0;
        }


        public async Task<bool> BatchUpdateAsync(Expression<Func<TEntity, bool>> where,
            Expression<Func<TEntity, TEntity>> updateFactory)
        {

            var bindings = ((MemberInitExpression)updateFactory.Body).Bindings.ToList();

            if (typeof(IAuditUpdate).IsAssignableFrom(typeof(TEntity)))
            {
                var hasPropNameList = bindings.Select(t => t.Member.Name).ToList();

                if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateTime)))
                {
                    bindings.Add(Expression.Bind(typeof(TEntity).GetMember(nameof(IAuditUpdate.UpdateTime))[0], Expression.Constant(DateTime.Now)));

                }

                if (!hasPropNameList.Contains( nameof(IAuditUpdate.UpdateUserId)))
                {
                    bindings.Add(Expression.Bind(typeof(TEntity).GetMember(nameof(IAuditUpdate.UpdateUserId))[0], Expression.Constant(_userInfo.Id)));

                }
            }


            var member = Expression.MemberInit(Expression.New(typeof(TEntity)), bindings);

            var factory = Expression.Lambda<Func<TEntity, TEntity>>(member, Expression.Parameter(typeof(TEntity), "x"));


            return await _dbSet.IgnoreQueryFilters().Where(where).BatchUpdateAsync(factory) > 0;



        }





        #endregion



        #region 非异步部分

        public TEntity ImageFind(Guid id, Type type)
        {
            //重传的时候  状态为修改    上传的时候状态为添加  内存中有,就不要重复查询数据库了
            var list = _dbContext.ChangeTracker.Entries()
                  .Where(u => (u.State == EntityState.Added || u.State == EntityState.Modified) && (u.Entity.GetType() == type)).Select(t => t.Entity as TEntity);

            var entity = list.FirstOrDefault(t => t.Id == id);

            if (entity == null)
            {
                return _dbSet.FirstOrDefault(t => t.Id == id);
            }
            else
            {
                return entity;
            }

        }

        public IQueryable<TEntity> AsQueryable(bool ignoreQueryFilters = false)
        {
            var query = _dbSet.AsQueryable();

            if (ignoreQueryFilters)
            {
                query = query.IgnoreQueryFilters();
            }

            return query.AsNoTracking();
        }

        public IQueryable<TResult> Select<TResult>(Expression<Func<TEntity, TResult>> selector)
        {
            return _dbSet.AsNoTracking().Select(selector);
        }

        public IQueryable<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> filter)
        {
            return condition ? _dbSet.AsNoTracking().Where(filter) : _dbSet.AsNoTracking();
        }

        public IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> exp = null, bool isTraking = false, bool ignoreQueryFilters = false)
        {
            IQueryable<TEntity> query = _dbSet;

            if (!isTraking)
            {
                query = query.AsNoTracking();
            }

            if (ignoreQueryFilters)
            {
                query = query.IgnoreQueryFilters();
            }

            if (exp != null)
            {
                query = query.Where(exp);
            }
            return query;
        }

        public EntityEntry Entry(TEntity t)
        {
            return _dbContext.Entry(t);
        }

        public EntityEntry<TEntity> Attach(TEntity entity)
        {
            return _dbSet.Attach(entity);
        }

        public void Detached(TEntity t)
        {
            _dbContext.Entry(t).State = EntityState.Detached;
        }


        //  automapper 相关
        public IQueryable<TDestination> ProjectTo<TDestination>(IConfigurationProvider configuration, object parameters, params Expression<Func<TDestination, object>>[] membersToExpand)
        {
            return _dbSet.AsNoTracking().ProjectTo(configuration, parameters, membersToExpand);
        }

        public IQueryable<TDestination> ProjectTo<TDestination>(IConfigurationProvider configuration, params Expression<Func<TDestination, object>>[] membersToExpand)
        {
            return _dbSet.AsNoTracking().ProjectTo(configuration, membersToExpand);
        }

        public IQueryable<TDestination> ProjectTo<TDestination>(IConfigurationProvider configuration, IDictionary<string, object> parameters, params string[] membersToExpand)
        {
            return _dbSet.AsNoTracking().ProjectTo<TDestination>(configuration, parameters, membersToExpand);
        }

        /// <summary>
        /// 仅仅供字典表插入使用,因为efcore 动态映射列的问题
        /// </summary>
        /// <typeparam name="TFrom"></typeparam>
        /// <param name="from"></param>
        /// <param name="verify"></param>
        /// <returns></returns>
        /// <exception cref="BusinessValidationFailedException"></exception>
        public async Task<TEntity> InsertDictionaryAsync<TFrom>(TFrom from, params EntityVerifyExp<TEntity>[] verify)
        {
            var entity = _mapper.Map<TEntity>(from);


            foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify))
            {
                if (await _dbSet.IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
                {
                    throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
                }
            }

            if (typeof(TEntity) == typeof(Dictionary))
            {
                Type type = typeof(TFrom);

                //以下是不要ID这个字段的  比如自增列ID  就不能像上名那样写   
                var properties = type.GetProperties().Where(t => t.Name != "Id");


                string strSqlName = string.Join(",", properties.Select(p => $"[{p.Name}]").ToArray());

                string strSqlValue = string.Join(",", properties.Select(P => $"@{P.Name}").ToArray());

                string strSql = $"insert into {nameof(Dictionary)} ( " + strSqlName + " ) values (" + strSqlValue + ")";

                //para Sql是参数
                SqlParameter[] para = properties.Select(p => new SqlParameter($"@{p.Name}", p.GetValue(from, null))).ToArray();


                _dbContext.Database.ExecuteSqlRaw(strSql, para);

                return entity;
            }
            else
            {
                throw new Exception("仅仅供字典表插入使用,因为efcore 动态映射列的问题");
                //await _dbSet.BulkInsertAsync(new List<TEntity>() { entity });

                //return entity;
            }
        }

        #endregion
    }

}