using Dpz.Core.Public.ViewModel.Request;
using Dpz.Core.Public.ViewModel.Response;
namespace Dpz.Core.Service.RepositoryServiceImpl;
public class UserHistoryService(IRepository<UserHistory> repository) : IUserHistoryService
{
public async Task<IPagedList<UserHistoryResponse>> GetPagedListAsync(UserHistoryRequest request)
{
var filterEmpty = Builders<UserHistory>.Filter.Empty;
var filters = new List<FilterDefinition<UserHistory>>();
if (!string.IsNullOrEmpty(request.Account))
{
var accountFilter = Builders<UserHistory>.Filter.Regex(
x => x.Account,
new BsonRegularExpression(request.Account, "i")
);
filters.Add(accountFilter);
}
if (request.ChangeTimeStart.HasValue)
{
var startFilter = Builders<UserHistory>.Filter.Gte(
x => x.ChangeTime,
request.ChangeTimeStart.Value
);
filters.Add(startFilter);
}
if (request.ChangeTimeEnd.HasValue)
{
var endFilter = Builders<UserHistory>.Filter.Lte(
x => x.ChangeTime,
request.ChangeTimeEnd.Value
);
filters.Add(endFilter);
}
if (!string.IsNullOrEmpty(request.ChangeProperty))
{
var propertyFilter = Builders<UserHistory>.Filter.AnyIn(
x => x.Changes.Select(y => y.Field),
[request.ChangeProperty]
);
filters.Add(propertyFilter);
}
var filterResult =
filters.Count > 0 ? Builders<UserHistory>.Filter.And(filters) : filterEmpty;
return await repository
.SearchFor(filterResult)
.SortByDescending(x => x.Id)
.ToPagedListAsync<UserHistory, UserHistoryResponse>(
request.PageIndex,
request.PageSize
);
}
public async Task<List<string>> GetChangedPropertiesAsync()
{
return await repository
.MongodbQueryable.SelectMany(x => x.Changes)
.GroupBy(x => x.Field)
.Select(x => x.Key)
.ToListAsync();
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这是一个基于 MongoDB 驱动和仓储(repository)模式实现的服务类,用来查询用户历史(UserHistory)记录并导出已变更的字段名。类实现了两个异步方法:GetPagedListAsync 和 GetChangedPropertiesAsync。下面分项说明其功能、流程以及几点注意/改进建议。
总体结构
- 构造函数注入:IRepository
repository(通过记录可对 MongoDB 集合进行查询)。 - 目标:根据请求参数筛选、分页并返回 UserHistory 的分页响应;以及获取所有变更字段名的列表。
方法 1 — GetPagedListAsync(UserHistoryRequest request) 功能:根据 request 中的筛选条件(账号模糊匹配、变更时间范围、变更属性)构建 MongoDB 过滤器,按 Id 降序分页并把结果映射为 UserHistoryResponse 返回 IPagedList。
流程(代码逻辑):
- 初始化空过滤(filterEmpty)和一个 FilterDefinition 列表 filters。
- 如果 request.Account 非空,添加一个正则(不区分大小写)过滤,匹配 Account 字段(模糊匹配)。
- 如果 request.ChangeTimeStart 有值,添加 ChangeTime >= start 的过滤。
- 如果 request.ChangeTimeEnd 有值,添加 ChangeTime <= end 的过滤。
- 如果 request.ChangeProperty 非空,期望添加“Changes 列表中存在 Field 等于该值”的过滤(原代码试图用 AnyIn)。
- 将多个过滤器用 Builders<...>.Filter.And 组合(若无条件则使用 Empty)。
- 用 repository.SearchFor(filterResult) 获取查询,按 Id 降序 SortByDescending(x => x.Id),然后调用 ToPagedListAsync<UserHistory, UserHistoryResponse>(pageIndex, pageSize) 做分页并把实体映射到响应模型,最终返回分页结果。
方法 2 — GetChangedPropertiesAsync() 功能:返回集合中 Changes 子文档里所有不同的 Field 值(即所有曾被更改过的属性名)。
实现思路:
- 通过 repository.MongodbQueryable.SelectMany(x => x.Changes) 将所有 UserHistory 的 Changes 展开为一个元素序列。
- GroupBy 按 Field 分组并 Select Key,从而得到不同的字段名列表,最后 ToListAsync() 返回 List
。
需要注意的问题与改进建议
原代码中针对 ChangeProperty 的过滤写法有错误/不可用:
- 表达式 Builders
.Filter.AnyIn(x => x.Changes.Select(y => y.Field), [request.ChangeProperty]) 既不是合法的 C# 语法([request.ChangeProperty] 不是数组字面量),也不是 MongoDB 驱动期望的字段表达方式。 - 推荐正确写法(任选其一): a) 使用 ElemMatch: var propertyFilter = Builders
.Filter.ElemMatch(u => u.Changes, c => c.Field == request.ChangeProperty); b) 使用字段路径匹配简单等值(当只需存在某个子文档的 Field 值时): var propertyFilter = Builders .Filter.Eq("Changes.Field", request.ChangeProperty); c) 如果想用 AnyIn(给定多个值),传入数组并用字段表达式(更复杂,通常不必): var propertyFilter = Builders .Filter.AnyIn("Changes.Field", new[] { request.ChangeProperty });
- 表达式 Builders
性能与索引建议:
- 如果频繁按 Account、ChangeTime 或 Changes.Field 查询,应在这些字段上建立索引(特别是 Changes.Field 是数组元素字段时,建立子字段索引)。
- SelectMany + GroupBy 会扫描大量数据,若数据量很大,考虑用 MongoDB 的 distinct 或聚合管道(Aggregate)来做去重以节省内存/IO:collection.DistinctAsync
("Changes.Field", filter)。
其它可改进点:
- 验证并规范化 request.PageIndex/PageSize,防止异常或非常大的 pageSize。
- 支持 CancellationToken 以便取消长时间查询。
- 如果 ToPagedListAsync 包含映射逻辑,确认映射配置(AutoMapper 等)正确无误。
- 考虑对正则查询(Account)进行预处理或只在必要时使用,正则查询可能无法利用普通索引(除非为前缀查询或建立 text 索引)。
总结
- GetPagedListAsync:按可选条件(账号模糊、时间区间、变更属性)构建过滤器,按 Id 降序分页并映射到响应模型返回。
- GetChangedPropertiesAsync:返回 Changes 子文档中所有不同的 Field 名称。
- 代码中关于 Changes.Field 的过滤写法需要修正,且在大数据量时需注意索引和查询效率。
评论加载中...