using Dpz.Core.MessageQueue.Abstractions;
using Dpz.Core.Public.ViewModel.Messages;
using Dpz.Core.Public.ViewModel.RequestEvent;
namespace Dpz.Core.Service.RepositoryServiceImpl;
public class TimelineService(
IRepository<Timeline> repository,
IMapper mapper,
IMediator mediator,
IFusionCache fusionCache,
IMessagePublisher<DeleteMarkdownMessage> deleteMarkdownPublisher
) : AbstractCacheService(fusionCache), ITimelineService
{
public async Task<List<VmTimeline>> GetTimelinesAsync(
string account,
CancellationToken cancellationToken = default
)
{
return await GetOrSetCacheAsync<List<VmTimeline>>(
nameof(GetTimelinesAsync),
async (_, ct) =>
{
var list = await repository
.SearchFor(x => x.Author.Id == account)
.OrderByDescending(x => x.Date)
.ThenByDescending(x => x.CreateTime)
.ToListAsync(ct);
return mapper.Map<List<VmTimeline>>(list);
},
new { account },
cancellationToken: cancellationToken
);
}
public async Task SaveAsync(VmTimeline viewModel, CancellationToken cancellationToken = default)
{
var entity = mapper.Map<Timeline>(viewModel);
if (entity == null)
{
throw new ArgumentException("viewModel is null", nameof(viewModel));
}
if (entity.Id != ObjectId.Empty)
{
entity = await repository.TryGetAsync(
viewModel.Id,
cancellationToken: cancellationToken
);
if (entity == null)
{
return;
}
var request = new EditMarkdownRequest
{
Markdown = viewModel.Content,
OriginalMarkdown = entity.Content,
};
await mediator.Send(request, cancellationToken);
var update = Builders<Timeline>
.Update.Set(x => x.Title, viewModel.Title)
.Set(x => x.Content, viewModel.Content)
.Set(x => x.Date, viewModel.Date)
.Set(x => x.More, viewModel.More)
.Set(x => x.LastUpdateTime, DateTime.Now);
await repository.UpdateAsync(x => x.Id == entity.Id, update, cancellationToken);
await RemoveByPrefixAsync(cancellationToken);
return;
}
await repository.InsertAsync(entity, cancellationToken);
await RemoveByPrefixAsync(cancellationToken);
}
public async Task DeleteAsync(string[] id, CancellationToken cancellationToken = default)
{
var ids = id.Select(x => ObjectId.TryParse(x, out var oid) ? oid : (ObjectId?)null)
.Where(x => x.HasValue)
.Select(x => x!.Value)
.ToList();
var filter = Builders<Timeline>.Filter.In(x => x.Id, ids);
var list = await repository.SearchFor(filter).ToListAsync(cancellationToken);
var contents = list.Select(x => x.Content).Where(x => !string.IsNullOrEmpty(x)).ToList();
// 发布消息到队列,异步处理 Markdown 中的图片删除
if (contents.Count > 0)
{
await deleteMarkdownPublisher.PublishAsync(
new DeleteMarkdownMessage { MarkdownContents = contents },
cancellationToken: cancellationToken
);
}
await repository.DeleteAsync(filter, cancellationToken);
await RemoveByPrefixAsync(cancellationToken);
}
public async Task<IPagedList<VmTimeline>> GetPageAsync(
int pageIndex,
int pageSize,
string? content = null,
string? account = null,
CancellationToken cancellationToken = default
)
{
return await GetOrSetPagedListAsync<VmTimeline>(
nameof(GetPageAsync),
async (_, _) =>
{
var predicate = repository.SearchFor(x => true);
if (!string.IsNullOrEmpty(content))
{
predicate = predicate.Where(x =>
x.Title.Contains(content) || x.Content.Contains(content)
);
}
if (!string.IsNullOrEmpty(account))
{
predicate = predicate.Where(x => x.Author.Id == account);
}
return await predicate
.OrderByDescending(x => x.Date)
.ToPagedListAsync<Timeline, VmTimeline>(pageIndex, pageSize, cancellationToken);
},
new
{
pageIndex,
pageSize,
content,
account,
},
cancellationToken: cancellationToken
);
}
public async Task<VmTimeline?> FindAsync(
string id,
CancellationToken cancellationToken = default
)
{
return await GetOrSetCacheAsync<VmTimeline?>(
nameof(FindAsync),
async (_, ct) =>
{
var entity = await repository.TryGetAsync(id, cancellationToken: ct);
return entity == null ? null : mapper.Map<VmTimeline>(entity);
},
new { id },
cancellationToken: cancellationToken
);
}
protected override TimeSpan CacheDefaultExpiration => TimeSpan.FromDays(7);
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这是一个时间线服务类的实现,主要用于管理时间线数据的CRUD操作。让我详细解释一下这个代码:
类结构和依赖注入
public class TimelineService(
IRepository<Timeline> repository,
IMapper mapper,
IMediator mediator,
IFusionCache fusionCache,
IMessagePublisher<DeleteMarkdownMessage> deleteMarkdownPublisher
) : AbstractCacheService(fusionCache), ITimelineService
这个类继承自 AbstractCacheService 并实现了 ITimelineService 接口,使用了C# 12的主构造函数语法。依赖注入了:
IRepository<Timeline>: 数据仓储接口IMapper: 对象映射器(AutoMapper)IMediator: 中介者模式实现(MediatR)IFusionCache: 缓存服务IMessagePublisher<DeleteMarkdownMessage>: 消息发布器
主要方法分析
1. GetTimelinesAsync - 获取用户时间线列表
public async Task<List<VmTimeline>> GetTimelinesAsync(string account, CancellationToken cancellationToken = default)
- 根据用户账号获取时间线列表
- 使用缓存机制提高性能
- 按日期和创建时间降序排序
2. SaveAsync - 保存时间线
public async Task SaveAsync(VmTimeline viewModel, CancellationToken cancellationToken = default)
- 支持新增和更新操作
- 如果实体ID不为空,执行更新操作:
- 发送
EditMarkdownRequest到中介者处理Markdown编辑 - 使用MongoDB的Update构建器更新特定字段
- 发送
- 如果是新实体,直接插入
- 操作完成后清除相关缓存
3. DeleteAsync - 删除时间线
public async Task DeleteAsync(string[] id, CancellationToken cancellationToken = default)
- 批量删除时间线
- 将字符串ID转换为ObjectId
- 提取要删除记录中的Markdown内容
- 通过消息队列异步处理Markdown中的图片删除
- 删除数据库记录并清除缓存
4. GetPageAsync - 分页查询
public async Task<IPagedList<VmTimeline>> GetPageAsync(...)
- 支持分页查询
- 可按内容和账号进行过滤
- 使用缓存机制
- 按日期降序排序
5. FindAsync - 查找单个时间线
public async Task<VmTimeline?> FindAsync(string id, CancellationToken cancellationToken = default)
- 根据ID查找单个时间线
- 使用缓存机制
- 返回可空的VmTimeline对象
设计特点
- 缓存策略: 继承自
AbstractCacheService,所有查询操作都使用缓存,默认缓存7天 - 异步处理: 删除操作中的图片清理通过消息队列异步处理,避免阻塞主流程
- 数据映射: 使用AutoMapper在实体和视图模型之间转换
- 错误处理: 对无效输入进行验证和异常处理
- MongoDB集成: 使用MongoDB特定的操作如ObjectId、Builders等
- 中介者模式: 使用MediatR处理复杂的业务逻辑(如Markdown编辑)
这是一个典型的现代.NET应用服务层实现,体现了依赖注入、缓存、异步处理、消息队列等最佳实践。
评论加载中...