using System.Application.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace System.Application.Repositories
{
///
/// 仓储接口定义
///
public interface IRepository
{
protected static async Task OperateRangeAsync(
IEnumerable entities,
Func> operate)
=> (await Task.WhenAll(entities.Select(operate))).Sum();
protected static async IAsyncEnumerable<(int rowCount, T entity)> OperateRangeAsyncEnumerable(
IEnumerable entities,
Func> operate)
{
foreach (var entity in entities)
{
var rowCount = await operate(entity);
yield return (rowCount, entity);
}
}
protected static async IAsyncEnumerable<(int rowCount, DbRowExecResult result, T entity)> OperateRangeAsyncEnumerable(
IEnumerable entities,
Func> operate)
{
foreach (var entity in entities)
{
var (rowCount, logic) = await operate(entity);
yield return (rowCount, logic, entity);
}
}
}
///
public interface IRepository : IRepository where TEntity : class
{
#region 增(Insert Funs) 立即执行并返回受影响的行数
///
/// 将实体插入到数据库中
///
/// 要添加的实体
/// 受影响的行数
Task InsertAsync(TEntity entity);
///
/// 将多个实体插入到数据库中
///
/// 要添加的多个实体
/// 受影响的行数
public Task InsertRangeAsync(IEnumerable entities) => OperateRangeAsync(entities, InsertAsync);
///
public Task InsertRangeAsync(params TEntity[] entities) => InsertRangeAsync(entities.AsEnumerable());
#endregion
#region 删(Delete Funs) 立即执行并返回受影响的行数
///
/// 将实体从数据库中删除
///
/// 要删除的实体
/// 受影响的行数
Task DeleteAsync(TEntity entity);
///
/// 将多个实体从数据库中删除
///
/// 要删除的多个实体
/// 受影响的行数
public Task DeleteRangeAsync(IEnumerable entities) => OperateRangeAsync(entities, DeleteAsync);
///
public Task DeleteRangeAsync(params TEntity[] entities) => DeleteRangeAsync(entities.AsEnumerable());
#endregion
#region 改(Update Funs) 立即执行并返回受影响的行数
///
/// 将实体更新到数据库中
///
/// 要更新的实体
/// 受影响的行数
Task UpdateAsync(TEntity entity);
///
/// 将多个实体更新到数据库中
///
/// 要更新的多个实体
/// 受影响的行数
public Task UpdateRangeAsync(IEnumerable entities) => OperateRangeAsync(entities, UpdateAsync);
///
public Task UpdateRangeAsync(params TEntity[] entities) => UpdateRangeAsync(entities.AsEnumerable());
#endregion
#region 查(通用查询)
///
/// 返回序列中满足指定的条件或默认值,如果找到这样的元素的第一个元素
///
/// 用于测试每个元素是否满足条件的函数
///
/// default(TEntity) 如果 集合 为空,或者如果没有元素通过由指定的测试 ;
/// 否则为中的第一个元素 集合 通过由指定的测试
///
///
/// 集合 或 为
///
Task FirstOrDefaultAsync(Expression> predicate);
#endregion
}
///
public interface IRepository : IRepository, IGetPrimaryKey
where TEntity : class, IEntity
where TPrimaryKey : IEquatable
{
protected static bool IsDefault(TPrimaryKey primaryKey)
{
if (primaryKey == null) return true; // null is default
TPrimaryKey defPrimaryKey = default;
if (defPrimaryKey == null) return false; // primaryKey not null
return EqualityComparer.Default.Equals(primaryKey, defPrimaryKey);
}
protected static Expression> LambdaEqualId(TPrimaryKey primaryKey)
{
var parameter = Expression.Parameter(typeof(TEntity));
var left = Expression.PropertyOrField(parameter, nameof(IEntity.Id));
var right = Expression.Constant(primaryKey, typeof(TPrimaryKey));
var body = Expression.Equal(left, right);
return Expression.Lambda>(body, parameter);
}
#region 删(Delete Funs) 立即执行并返回受影响的行数
///
/// 根据主键将实体从数据库中删除
///
/// 要删除的实体主键
/// 受影响的行数
Task DeleteAsync(TPrimaryKey primaryKey);
///
/// 根据主键将多个实体从数据库中删除
///
/// 要删除的多个实体主键
/// 受影响的行数
public Task DeleteRangeAsync(IEnumerable primaryKeys) => OperateRangeAsync(primaryKeys, DeleteAsync);
///
public Task DeleteRangeAsync(params TPrimaryKey[] primaryKeys) => DeleteRangeAsync(primaryKeys.AsEnumerable());
///
public IAsyncEnumerable<(int rowCount, TPrimaryKey entity)> DeleteRangeAsyncEnumerable(IEnumerable primaryKeys)
=> OperateRangeAsyncEnumerable(primaryKeys, DeleteAsync);
///
public IAsyncEnumerable<(int rowCount, TPrimaryKey entity)> DeleteRangeAsyncEnumerable(params TPrimaryKey[] primaryKeys)
=> DeleteRangeAsyncEnumerable(primaryKeys.AsEnumerable());
#endregion
#region 查(通用查询)
///
/// 根据主键查询实体
///
/// 要查询的实体主键
/// 查询到的实体
ValueTask FindAsync(TPrimaryKey primaryKey);
///
/// 判断实体是否已经存在
///
/// 要查询的实体
/// 要查询的实体主键
/// 实体是否存在数据库中
public async ValueTask ExistAsync(TPrimaryKey primaryKey)
{
var entity = await FindAsync(primaryKey);
return entity != null;
}
///
public ValueTask ExistAsync(TEntity entity)
{
var primaryKey = GetPrimaryKey(entity);
return ExistAsync(primaryKey);
}
#endregion
#region 增或改(InsertOrUpdate Funs) 立即执行并返回受影响的行数
///
/// 新增或更新实体
///
/// 要新增或更新的实体
/// 受影响的行数与数据库逻辑
public async Task<(int rowCount, DbRowExecResult result)> InsertOrUpdateAsync(TEntity entity)
{
var exist = await ExistAsync(entity);
int rowCount;
DbRowExecResult result;
if (exist)
{
rowCount = await UpdateAsync(entity);
result = DbRowExecResult.Update;
}
else
{
rowCount = await InsertAsync(entity);
result = DbRowExecResult.Insert;
}
return (rowCount, result);
}
///
/// 批量新增或更新实体
///
/// 要新增或更新的多个实体
///
public IAsyncEnumerable<(int rowCount, DbRowExecResult result, TEntity entity)> InsertOrUpdateAsync(IEnumerable entities)
=> OperateRangeAsyncEnumerable(entities, InsertOrUpdateAsync);
///
public IAsyncEnumerable<(int rowCount, DbRowExecResult result, TEntity entity)> InsertOrUpdateAsync(params TEntity[] entities)
=> InsertOrUpdateAsync(entities.AsEnumerable());
#endregion
}
}