using CsvHelper;
using Microsoft.Net.Http.Headers;
using NetAdmin.Application.Repositories;
using NetAdmin.Domain;
using NetAdmin.Domain.Dto.Dependency;
namespace NetAdmin.Application.Services;
///
/// 仓储服务基类
///
/// 实体类型
/// 主键类型
/// 日志类型
public abstract class RepositoryService(BasicRepository rpo)
: ServiceBase
where TEntity : EntityBase //
where TPrimary : IEquatable
{
///
/// 默认仓储
///
protected BasicRepository Rpo => rpo;
///
/// 启用级联保存
///
protected bool EnableCascadeSave {
get => Rpo.DbContextOptions.EnableCascadeSave;
set => Rpo.DbContextOptions.EnableCascadeSave = value;
}
///
/// 导出实体
///
protected static async Task ExportAsync( //
Func, ISelectGrouping> selector, QueryReq query, string fileName
, Expression, object>> listExp = null)
where TQuery : DataAbstraction, new()
{
var list = await selector(query).Take(Numbers.MAX_LIMIT_EXPORT).ToListAsync(listExp).ConfigureAwait(false);
return await GetExportFileStreamAsync(fileName, list).ConfigureAwait(false);
}
///
/// 导出实体
///
protected static async Task ExportAsync( //
Func, ISelect> selector, QueryReq query, string fileName
, Expression> listExp = null)
where TQuery : DataAbstraction, new()
{
var select = selector(query)
#if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
.Take(Numbers.MAX_LIMIT_EXPORT);
object list = listExp == null
? await select.ToListAsync().ConfigureAwait(false)
: await select.ToListAsync(listExp).ConfigureAwait(false);
return await GetExportFileStreamAsync(fileName, list).ConfigureAwait(false);
}
///
/// 更新实体
///
/// 新的值
/// 包含的属性
/// 排除的属性
/// 查询表达式
/// 查询sql
/// 是否忽略版本锁
/// 更新行数
protected Task UpdateAsync( //
TEntity newValue //
, IEnumerable includeFields //
, string[] excludeFields = null //
, Expression> whereExp = null //
, string whereSql = null //
, bool ignoreVersion = false)
{
// 默认匹配主键
whereExp ??= a => a.Id.Equals(newValue.Id);
var update = BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion).Where(whereExp).Where(whereSql);
return update.ExecuteAffrowsAsync();
}
#if DBTYPE_SQLSERVER
///
/// 更新实体
///
/// 新的值
/// 包含的属性
/// 排除的属性
/// 查询表达式
/// 查询sql
/// 是否忽略版本锁
/// 更新后的实体列表
protected Task> UpdateReturnListAsync( //
TEntity newValue //
, IEnumerable includeFields //
, string[] excludeFields = null //
, Expression> whereExp = null //
, string whereSql = null //
, bool ignoreVersion = false)
{
// 默认匹配主键
whereExp ??= a => a.Id.Equals(newValue.Id);
return BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion)
.Where(whereExp)
.Where(whereSql)
.ExecuteUpdatedAsync();
}
#endif
private static async Task GetExportFileStreamAsync(string fileName, object list)
{
var listTyped = list.Adapt>();
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
csv.WriteHeader();
await csv.NextRecordAsync().ConfigureAwait(false);
foreach (var item in listTyped) {
csv.WriteRecord(item);
await csv.NextRecordAsync().ConfigureAwait(false);
}
await csv.FlushAsync().ConfigureAwait(false);
_ = stream.Seek(0, SeekOrigin.Begin);
App.HttpContext.Response.Headers.ContentDisposition
= new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
}.ToString();
return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
}
private IUpdate BuildUpdate( //
TEntity entity //
, IEnumerable includeFields //
, string[] excludeFields = null //
, bool ignoreVersion = false)
{
var updateExp = includeFields == null
? Rpo.UpdateDiy.SetSource(entity)
: Rpo.UpdateDiy.SetDto(includeFields!.ToDictionary(
x => x
, x => typeof(TEntity).GetProperty(x, BindingFlags.Public | BindingFlags.Instance)!
.GetValue(entity)));
if (excludeFields != null) {
updateExp = updateExp.IgnoreColumns(excludeFields);
}
if (!ignoreVersion && entity is IFieldVersion ver) {
updateExp = updateExp.Where($"{nameof(IFieldVersion.Version)} = @version", new { version = ver.Version });
}
return updateExp;
}
}