EI-Image-Viewer-Api/IRaCIS.Core.Infra.EFCore/Repository/IRepository.cs

464 lines
15 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using AutoMapper;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using IRaCIS.Core.Domain.Share;
using EFCore.BulkExtensions;
using Microsoft.Extensions.Localization;
namespace IRaCIS.Core.Infra.EFCore
{
#region 泛型通用版本
public interface IRepository
{
IQueryable<T> GetQueryable<T>(bool ignoreQueryFilters = false) where T : Entity;
DbSet<T> Set<T>() where T : Entity;
EntityEntry<T> Entry<T>(T t) where T : Entity;
Task<bool> SaveChangesAsync();
IQueryable<T> WhereIf<T>(bool condition, Expression<Func<T, bool>> filter) where T : Entity;
Task<bool> AnyAsync<T>(Expression<Func<T, bool>> filter, bool ignoreQueryFilters = false) where T : Entity;
/// <summary>
///不跟踪 查询单个实体不会出现NUll
/// </summary>
/// <param name="exp"></param>
/// <param name="ignoreQueryFilters"></param>
/// <returns></returns>
Task<T> FirstAsync<T>(Expression<Func<T, bool>> exp = null, bool isTracking = false, bool ignoreQueryFilters = false) where T : Entity;
Task<T> FirstOrDefaultAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity;
Task<int> CountAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity;
IQueryable<T> Where<T>(Expression<Func<T, bool>> exp = null, bool isTraking = false, bool ignoreQueryFilters = false) where T : Entity;
ValueTask<T> FindAsync<T>(Guid id) where T : Entity;
Task<T> InsertOrUpdateAsync<T, TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<T>[] verify) where T : Entity;
Task<T> InsertFromDTOAsync<T, TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<T>[] verify) where T : Entity;
Task<T> UpdateFromDTOAsync<T, TFrom>(TFrom from, bool autoSave = false, bool ignoreDtoNullProperty = true, params EntityVerifyExp<T>[] verify) where T : Entity;
ValueTask<T> AddAsync<T>(T entity, bool autoSave = false) where T : Entity;
Task UpdateRange<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity;
Task<bool> AddRangeAsync<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity;
Task<bool> UpdateAsync<T>(T entity, bool autoSave = false) where T : Entity;
Task<bool> DeleteAsync<T>(T entity, bool autoSave = false) where T : Entity;
Task<bool> BatchDeleteAsync<T>(Expression<Func<T, bool>> deleteFilter) where T : Entity;
Task<bool> BatchUpdateAsync<T>(Expression<Func<T, bool>> where, Expression<Func<T, T>> updateFactory) where T : Entity;
Task UpdatePartialFromQueryAsync<T>(Expression<Func<T, bool>> updateFilter,
Expression<Func<T, T>> updateFactory,
bool autoSave = false, bool ignoreQueryFilter = false) where T : Entity;
}
public class Repository : IRepository
{
#region 构造 基本
private IRaCISDBContext _dbContext { get; }
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
public IStringLocalizer _localizer { get; set; }
public Repository(IRaCISDBContext dbContext, IMapper mapper, IUserInfo userInfo, IStringLocalizer localizer)
{
_localizer = localizer;
_dbContext = dbContext;
_mapper = mapper;
_userInfo = userInfo;
}
/// <summary>
/// 设置是使用哪个仓储 默认不跟踪
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="isTraking"></param>
/// <returns></returns>
public IQueryable<T> GetQueryable<T>(bool ignoreQueryFilters = false) where T : Entity
{
IQueryable<T> query = _dbContext.Set<T>();
if (ignoreQueryFilters)
{
query = query.IgnoreQueryFilters();
}
return query.AsNoTracking();
}
public DbSet<T> Set<T>() where T : Entity
{
return _dbContext.Set<T>();
}
public EntityEntry<T> Entry<T>(T t) where T : Entity
{
return _dbContext.Entry<T>(t);
}
public IQueryable<T> WhereIf<T>(bool condition, Expression<Func<T, bool>> filter) where T : Entity
{
IQueryable<T> query = _dbContext.Set<T>().AsNoTracking();
return condition ? query.Where(filter) : query;
}
private async Task<bool> SaveChangesAsync(bool autoSave)
{
if (autoSave)
{
return await SaveChangesAsync();
}
else
{
return false;
}
}
public async Task<bool> SaveChangesAsync()
{
return await _dbContext.SaveChangesAsync().ConfigureAwait(false) > 0;
}
#endregion
public async Task<T> InsertFromDTOAsync<T, TFrom>(TFrom from, bool autoSave = false,
params EntityVerifyExp<T>[] verify) where T : Entity
{
var entity = _mapper.Map<T>(from);
await _dbContext.EntityVerifyAsync(true, verify);
entity = await AddAsync(entity, autoSave);
return entity;
}
public async Task<T> UpdateFromDTOAsync<T, TFrom>(TFrom from, bool autoSave = false, bool ignoreDtoNullProperty = true, params EntityVerifyExp<T>[] verify) where T : Entity
{
var entity = _mapper.Map<T>(from);
await _dbContext.EntityVerifyAsync(false, verify, entity.Id);
var dbEntity = await _dbContext.Set<T>().IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == entity.Id).ConfigureAwait(false);
if (dbEntity == null)
{
throw new BusinessValidationFailedException(_localizer["Repository_UpdateError"]);
}
var dbBeforEntity = dbEntity.Clone();
_mapper.Map(from, dbEntity);
//DTO null 属性不更新 防止意外操作,导致保存数据错误,或者 add 和update 用一个模型更新的时候只传递了部分字段导致不想更新的字段因为没传递值用null覆盖了
// Guid属性 为null 时 映射到 Guid 时 默认会变成 Guid.Empty
if (ignoreDtoNullProperty)
{
var dbEntityProp = typeof(T).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;
}
public async Task<T> InsertOrUpdateAsync<T, TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<T>[] verify) where T : Entity
{
var entity = _mapper.Map<T>(from);
if (entity.Id == Guid.Empty)
{
return await InsertFromDTOAsync(from, autoSave, verify);
}
else
{
return await UpdateFromDTOAsync(from, autoSave, false, verify);
}
}
public async Task<bool> AnyAsync<T>(Expression<Func<T, bool>> filter, bool ignoreQueryFilters = false) where T : Entity
{
var query = _dbContext.Set<T>().AsQueryable();
if (ignoreQueryFilters)
{
query = query.IgnoreQueryFilters();
}
return await query.AsNoTracking().AnyAsync(filter).ConfigureAwait(false);
}
#region 基本查询 异步
/// <summary>
/// 跟踪查询某个实体 --异步 默认是跟踪查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="exp"></param>
/// <returns></returns>
///
public async Task<int> CountAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity
{
var query = _dbContext.Set<T>().AsQueryable();
if (ignoreQueryFilters)
{
query = query.IgnoreQueryFilters();
}
if (exp != null)
{
query = query.Where(exp);
}
return await query.CountAsync().ConfigureAwait(false);
}
public async Task<T> FirstAsync<T>(Expression<Func<T, bool>> exp = null, bool isTracking = false, bool ignoreQueryFilters = false) where T : Entity
{
var query = _dbContext.Set<T>().AsQueryable();
if (!isTracking)
{
query = query.AsNoTracking();
}
if (ignoreQueryFilters)
{
query = query.IgnoreQueryFilters();
}
var entity = await query.FirstOrDefaultAsync();
if (entity is null)
{
throw new QueryBusinessObjectNotExistException($"The query object {typeof(T).Name} does not exist in database, Please check the query parameters");
}
else
{
return entity;
}
}
public async Task<T> FirstOrDefaultAsync<T>(Expression<Func<T, bool>> exp = null, bool ignoreQueryFilters = false) where T : Entity
{
var query = _dbContext.Set<T>().AsQueryable();
if (ignoreQueryFilters)
{
query = query.IgnoreQueryFilters();
}
if (exp != null)
{
query = query.Where(exp);
}
return await query.FirstOrDefaultAsync().ConfigureAwait(false);
}
/// <summary>
/// 过滤 默认不跟踪
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="exp"></param>
/// <param name="isTraking"></param>
/// <returns></returns>
public IQueryable<T> Where<T>(Expression<Func<T, bool>> exp = null, bool isTraking = false, bool ignoreQueryFilters = false) where T : Entity
{
IQueryable<T> query = _dbContext.Set<T>();
if (ignoreQueryFilters)
{
query = query.IgnoreQueryFilters();
}
if (!isTraking)
{
query = query.AsNoTracking();
}
if (exp != null)
{
query = query.Where(exp);
}
return query;
}
/// <summary>
/// 首先在内存中查找,其次再找数据库
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id"></param>
/// <returns></returns>
public async ValueTask<T> FindAsync<T>(Guid id) where T : Entity
{
return await _dbContext.Set<T>().FindAsync(id).ConfigureAwait(false);
}
#endregion
#region 基本添加、更新、删除 异步
public async ValueTask<T> AddAsync<T>(T entity, bool autoSave = false) where T : Entity
{
await _dbContext.Set<T>().AddAsync(entity).ConfigureAwait(false);
await SaveChangesAsync(autoSave);
return entity;
}
public async Task<bool> AddRangeAsync<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity
{
await _dbContext.Set<T>().AddRangeAsync(entities).ConfigureAwait(false);
return await SaveChangesAsync(autoSave);
}
public async Task UpdateRange<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity
{
_dbContext.Set<T>().UpdateRange(entities);
await SaveChangesAsync(autoSave);
}
public async Task<bool> UpdateAsync<T>(T entity, bool autoSave = false) where T : Entity
{
_dbContext.Set<T>().Update(entity);
return await SaveChangesAsync(autoSave);
}
public async Task<bool> DeleteAsync<T>(T entity, bool autoSave = false) where T : Entity
{
_dbContext.Set<T>().Remove(entity);
return await SaveChangesAsync(autoSave);
}
public async Task<bool> DeleteManyAsync<T>(IEnumerable<T> entities, bool autoSave = false) where T : Entity
{
_dbContext.Set<T>().RemoveRange(entities);
return await SaveChangesAsync(autoSave);
}
#endregion
public async Task<bool> BatchDeleteAsync<T>(Expression<Func<T, bool>> deleteFilter) where T : Entity
{
return await _dbContext.BatchDeleteNoTrackingAsync(deleteFilter);
}
public async Task<bool> BatchUpdateAsync<T>(Expression<Func<T, bool>> whereFilter, Expression<Func<T, T>> updateFactory) where T : Entity
{
return await _dbContext.BatchUpdateNoTrackingAsync(whereFilter, updateFactory, _userInfo.Id);
//return await _dbContext.Set<T>().IgnoreQueryFilters().Where(whereFilter).BatchUpdateAsync(updateFactory).ConfigureAwait(false) > 0;
}
public async Task UpdatePartialFromQueryAsync<T>(Expression<Func<T, bool>> updateFilter,
Expression<Func<T, T>> updateFactory,
bool autoSave = false, bool ignoreQueryFilter = false) where T : Entity
{
if (updateFilter == null)
{
throw new ArgumentException("更新过滤条件不允许为空", nameof(updateFilter));
}
var query = ignoreQueryFilter ? _dbContext.Set<T>().AsNoTracking().IgnoreQueryFilters() : _dbContext.Set<T>().AsNoTracking();
var searchEntityList = await query.Where(updateFilter).ToListAsync();
foreach (var needUpdateEntity in searchEntityList)
{
_dbContext.EntityModifyPartialFiled(needUpdateEntity, updateFactory);
}
await SaveChangesAsync(autoSave);
}
public async Task<bool> UpdateAsync<T>(T waitModifyEntity, Expression<Func<T, T>> updateFactory, bool autoSave = false) where T : Entity
{
_dbContext.EntityModifyPartialFiled(waitModifyEntity, updateFactory);
return await SaveChangesAsync(autoSave);
}
}
#endregion
}