没有基础的,请参考上一篇
彩蛋到最后一张图里找
参考链接
结果直接上图,没有任何业务代码
启动后,已经有了基本的CRUD功能,还扩展了批量删除,与动态查询
动态查询截图,支持分页,排序
实现原理:
FreeSql导航参考官方地址
聚合根(实验室) | FreeSql 官方文档
继承IReadOnlyRepository接口,实现用FreeSql实现所有功能即可
关键CRUD代码
//默认删除
public Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
{
return FreeSql.Delete<T>(new { Id = id }).ExecuteAffrowsAsync(cancellationToken);
}
public Task DeleteDirectAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return FreeSql.Delete<T>().Where(predicate).ExecuteAffrowsAsync(cancellationToken);
}
//批量删除
public Task DeleteManyAsync(IEnumerable<TKey> ids, bool autoSave = false, CancellationToken cancellationToken = default)
{
return FreeSql.Delete<T>(ids).ExecuteAffrowsAsync(cancellationToken);
}
//默认Get
public Task<T> GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
object dywhere = new { Id = id };
var query = FreeSql.GetAggregateRootRepository<T>().Select.WhereDynamic(dywhere);// FreeSql.Queryable<T>().WhereDynamic(dywhere);
FreeSqlHelper.SetNavigate(query);
return query.ToOneAsync(cancellationToken);
}
//默认GetList
public Task<IQueryable<T>> GetQueryableAsync()
{
ISelect<T> queryable;
if (_httpContextAccessor.HttpContext.Request.Query.Any(q => q.Key == "Sorting"))
{
string sorting = _httpContextAccessor.HttpContext.Request.Query["Sorting"];
queryable = FreeSql.Queryable<T>().OrderBy(sorting);
}
else
{
queryable = FreeSql.Queryable<T>();
}
FreeSqlHelper.SetNavigate(queryable);
return Task.FromResult(queryable.AsQueryable());
}
//默认Post
public async Task<T> InsertAsync(T entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
SetEntity(entity);
await FreeSql.GetAggregateRootRepository<T>().InsertAsync(entity,cancellationToken);
return entity;
}
FreeSqlHelper.cs代码
public class FreeSqlHelper
{
/// <summary>
/// 设置导航
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
public static void SetNavigate<T>(FreeSql.ISelect<T> query)
{
var type= typeof(T);
MemberInfo[] myMembers = type.GetProperties();
foreach (MemberInfo myMember in myMembers)
{
var navigateAttribute = myMember.GetCustomAttribute<FreeSql.DataAnnotations.NavigateAttribute>();
if (navigateAttribute != null)
{
query.IncludeByPropertyName(myMember.Name);
}
}
}
}
明细表id使用雪花漂移算法生成,引用Yitter.IdGenerator库(请自行nuget下载)
调用YitIdHelper.NextId()生成,没有数据库的自增字段功能,使用自增的问题很多
新增BaseCrudAppService类,代码直接从官方的CrudAppService里复制即可,利用批量替换,把CrudAppService替换为BaseCrudAppService
如图
新增FilterAsync与DeleteBulkAsync实现动态查询与批量删除功能
新增后的结果如图
freesql动态查询功能很强大,日期区间支持年,月,日期等,请参见下图示例说明
SearchCondition代码
public class SearchCondition
{
/// <summary>
/// 动态过滤条件
/// </summary>
public DynamicFilterInfo FilterInfo { get; set; }=new();
/// <summary>
/// 当前页
/// </summary>
public int CurrentPage { get; set; } = 1;
/// <summary>
/// 每页显示记录条数
/// </summary>
public int PageSize { get; set; } = 50;
/// <summary>
/// 排序
/// </summary>
public string Sorting { get; set; } = string.Empty;
}
IBaseRepository代码如图,只是为了在BaseCrudAppService能获取到freesql
Enum实体类代码,由代码生成器生成
[Serializable]
[Table("TSYS_Enum")]
public class Enum : BaseAuditedAggregateRoot<Guid>
{
/// <summary>
/// 字典群组
/// </summary>
public int EnumGroup { get; set; }
/// <summary>
/// 字典类型
/// </summary>
public int EnumType { get; set; } = 1;
/// <summary>
/// 字典代码
/// </summary>
[StringLength(100)]
public string EnumCode { get; set; }
/// <summary>
/// 说明
/// </summary>
[StringLength(100)]
public string EnumDesc { get; set; }
/// 备注
/// </summary>
[StringLength(500)]
public string Remark { get; set; }
/// <summary>
/// 数据状态 0:未提交,1:审核中,2:已审核
/// </summary>
public byte Status { get; set; }
/// <summary>
/// 禁用状态
/// </summary>
public byte ForbidStatus { get; set; }
/// <summary>
/// 禁用人
/// </summary>
public Guid? ForbidderId { get; set; }
/// <summary>
/// 禁用日期
/// </summary>
public DateTime? ForbidDate { get; set; }
/// <summary>
/// 审核人
/// </summary>
public Guid? ApproverId { get; set; }
/// <summary>
/// 审核日期
/// </summary>
public DateTime? ApproveDate { get; set; }
[FreeSql.DataAnnotations.Navigate(nameof(EnumItem.EnumId))]
public virtual List<EnumItem> Details { get; set; }
明细表实体类
[Serializable]
[Table("TSYS_EnumItem")]
public class EnumItem : CreationAuditedEntity<long>
{
/// <summary>
/// 主表key
/// </summary>
public Guid EnumId { get; set; }
/// <summary>
/// 显示值
/// </summary>
[StringLength(100)]
public string EnumItemName { get; set; }
/// <summary>
/// 存储值
/// </summary>
[StringLength(100)]
public string EnumItemValue { get; set; }
/// <summary>
/// 说明
/// </summary>
[StringLength(100)]
public string EnumItemDesc { get; set; }
/// <summary>
/// 行号
/// </summary>
public int Num { get; set; } = 1;
/// 备注
/// </summary>
[StringLength(500)]
public string Remark { get; set; }
/// <summary>
/// 数据状态 0:未提交,1:审核中,2:已审核
/// </summary>
public byte Status { get; set; }
/// <summary>
/// 禁用状态
/// </summary>
public byte ForbidStatus { get; set; }
/// <summary>
/// 禁用人
/// </summary>
public Guid? ForbidderId { get; set; }
/// <summary>
/// 禁用日期
/// </summary>
public DateTime? ForbidDate { get; set; }
/// <summary>
/// 审核人
/// </summary>
public Guid? ApproverId { get; set; }
/// <summary>
/// 审核日期
/// </summary>
public DateTime? ApproveDate { get; set; }
public virtual Enum Enum { get; set; }
}
把原来的CrudAppService改为BaseCrudAppService即可,这样只要继承了BaseCrudAppService所有的业务层,都有了,爽不爽啊,再也不用辛苦的做码农了。