namespace Dpz.Core.Service.RepositoryServiceImpl;

public class UserExtendedInfoService(IRepository<UserExtendedInfo> repository)
    : IUserExtendedInfoService
{
    public async Task<string> GetEmailAsync(
        string userId,
        CancellationToken cancellationToken = default
    )
    {
        if (string.IsNullOrWhiteSpace(userId))
        {
            return "";
        }

        var filter = Builders<UserExtendedInfo>.Filter.Eq(x => x.Id, userId);
        var entity = await repository
            .Collection.Find(filter)
            .SingleOrDefaultAsync(cancellationToken);
        return entity?.Email ?? "";
    }

    public async Task<Dictionary<string, string>> GetEmailMapAsync(
        IEnumerable<string> userIds,
        CancellationToken cancellationToken = default
    )
    {
        var userIdList = userIds
            .Where(x => !string.IsNullOrWhiteSpace(x))
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToList();
        if (userIdList.Count == 0)
        {
            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        }

        var filter = Builders<UserExtendedInfo>.Filter.In(x => x.Id, userIdList);
        var entities = await repository.Collection.Find(filter).ToListAsync(cancellationToken);
        return entities
            .Where(x => !string.IsNullOrWhiteSpace(x.Email))
            .ToDictionary(x => x.Id, x => x.Email ?? "", StringComparer.OrdinalIgnoreCase);
    }

    public async Task CreateIfMissingAsync(
        string userId,
        CancellationToken cancellationToken = default
    )
    {
        if (string.IsNullOrWhiteSpace(userId))
        {
            return;
        }

        var filter = Builders<UserExtendedInfo>.Filter.Eq(x => x.Id, userId);
        if (await repository.Collection.Find(filter).AnyAsync(cancellationToken))
        {
            return;
        }

        var now = DateTime.Now;
        var entity = new UserExtendedInfo
        {
            Id = userId,
            Email = "",
            WebAuthnCredentials = [],
            CreateTime = now,
            LastUpdateTime = now,
        };
        await repository.InsertAsync(entity, cancellationToken);
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

代码解释

这是一个使用 C# 编写的用户扩展信息服务类,采用了现代的 Primary Constructor(主构造函数)语法。以下是详细解释:

类定义

public class UserExtendedInfoService(IRepository<UserExtendedInfo> repository)
    : IUserExtendedInfoService
  • 使用依赖注入方式注入 IRepository<UserExtendedInfo> 仓储接口
  • 实现了 IUserExtendedInfoService 接口
  • 通过主构造函数直接声明依赖项(C# 12+ 特性)

主要方法

1. GetEmailAsync - 获取单个用户邮箱

public async Task<string> GetEmailAsync(string userId, CancellationToken cancellationToken)
  • 功能:根据用户ID查询用户邮箱
  • 逻辑
    • 参数验证:userId 为空则返回空字符串
    • 使用 MongoDB 的 Filter Builder 构建查询条件
    • 查询单条记录(SingleOrDefaultAsync
    • 返回邮箱或空字符串(使用空合并运算符 ??

2. GetEmailMapAsync - 批量获取用户邮箱映射

public async Task<Dictionary<string, string>> GetEmailMapAsync(IEnumerable<string> userIds, ...)
  • 功能:根据多个用户ID批量查询邮箱,返回字典映射
  • 逻辑
    • 过滤空值并去重(忽略大小写)
    • 列表为空则返回空字典
    • 使用 In 过滤器批量查询
    • 过滤掉邮箱为空的记录
    • 转换为忽略大小写的字典(Key: userId, Value: email)

3. EnsureAsync - 确保用户记录存在

public async Task EnsureAsync(string userId, CancellationToken cancellationToken)
  • 功能:确保指定用户ID的扩展信息记录存在,不存在则创建
  • 逻辑
    • 参数验证
    • 检查记录是否存在(AnyAsync
    • 不存在则创建新记录,包含:
      • 用户ID
      • 空邮箱
      • 空的 WebAuthn 凭证集合([] 集合表达式)
      • 创建时间和更新时间

技术特点

  1. 异步模式:所有方法都是异步的,支持 CancellationToken
  2. MongoDB 集成:使用 MongoDB Driver 的 Filter Builder 和异步 API
  3. 防御性编程:参数验证、空值处理
  4. 大小写不敏感:字典和比较使用 StringComparer.OrdinalIgnoreCase
  5. 现代 C# 语法:主构造函数、集合表达式 []、空合并运算符等

这是一个典型的数据访问层服务实现,遵循了依赖注入和异步编程的最佳实践。

评论加载中...