Files
TechHelper/TechHelper.Server/Services/QuestionService.cs
2025-06-20 15:37:39 +08:00

260 lines
7.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AutoMapper;
using Entities.Contracts;
using SharedDATA.Api;
using TechHelper.Services;
using System.Linq.Expressions;
using System.Linq;
using Entities; // 引入你的 Question 实体所在的命名空间
using Microsoft.EntityFrameworkCore;
using Entities.DTO; // 引入 EF Core 用于 Include (如果需要)
namespace TechHelper.Server.Services
{
public class QuestionService : IQuestionService
{
private readonly IUnitOfWork _work;
// 如果不再需要 AutoMapper 进行实体到 DTO 的映射,可以移除 _mapper 字段
// 但如果 AutoMapper 在其他服务中用于其他映射,或者将来可能需要,可以保留
private readonly IMapper _mapper;
private readonly IExamService _examService;
public QuestionService(IUnitOfWork work, IMapper mapper, IExamService examService)
{
_work = work;
_mapper = mapper;
_examService = examService;
}
public async Task<ApiResponse> AddAsync(Question model)
{
try
{
// 可以在此处进行业务逻辑校验,例如检查题目是否已存在
var existingQuestion = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
predicate: q => q.Title == model.Title && !q.IsDeleted
);
if (existingQuestion != null)
{
return ApiResponse.Error($"题目 '{model.Title}' 已存在,请勿重复添加。");
}
// 设置创建时间、创建者等通用属性
model.Id = Guid.NewGuid();
model.CreatedAt = DateTime.UtcNow;
model.UpdatedAt = DateTime.UtcNow;
model.IsDeleted = false;
await _work.GetRepository<Question>().InsertAsync(model);
await _work.SaveChangesAsync();
// 直接返回 Question 实体
return ApiResponse.Success("题目添加成功。", model);
}
catch (Exception ex)
{
return ApiResponse.Error($"添加题目失败: {ex.Message}");
}
}
public async Task<ApiResponse> DeleteAsync(Guid id)
{
try
{
var questionToDelete = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(predicate: q => q.Id == id && !q.IsDeleted);
if (questionToDelete == null)
{
return ApiResponse.Error($"找不到 ID 为 {id} 的题目,或者该题目已被删除。");
}
// 软删除
questionToDelete.IsDeleted = true;
questionToDelete.UpdatedAt = DateTime.UtcNow;
_work.GetRepository<Question>().Update(questionToDelete);
await _work.SaveChangesAsync();
return ApiResponse.Success($"ID 为 {id} 的题目已成功删除 (软删除)。");
}
catch (Exception ex)
{
return ApiResponse.Error($"删除题目时发生错误: {ex.Message}");
}
}
public async Task<ApiResponse> FindByTitle(string title)
{
try
{
var question = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
predicate: q => q.Title == title && !q.IsDeleted
);
if (question == null)
{
return ApiResponse.Error($"未找到题目 '{title}'。");
}
// 直接返回 Question 实体
return ApiResponse.Success(result: question);
}
catch (Exception ex)
{
return ApiResponse.Error($"查找题目时出现问题: {ex.Message}");
}
}
public async Task<ApiResponse> CheckTitlesExistence(IEnumerable<string> titles)
{
try
{
if (titles == null || !titles.Any())
{
return ApiResponse.Success("未指定查询的题目文本,返回空结果。", new Dictionary<string, bool>());
}
var distinctTitles = titles.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
var existingQuestions = await _work.GetRepository<Question>().GetAllAsync(
predicate: q => distinctTitles.Contains(q.Title) && !q.IsDeleted
);
var existingQuestionTexts = new HashSet<string>(existingQuestions.Select(q => q.Title), StringComparer.OrdinalIgnoreCase);
var resultDictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
foreach (var title in titles)
{
resultDictionary[title] = existingQuestionTexts.Contains(title);
}
return ApiResponse.Success(result: resultDictionary);
}
catch (Exception ex)
{
return ApiResponse.Error($"批量查找题目存在性时出现问题: {ex.Message}");
}
}
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
{
try
{
Expression<Func<Question, bool>> predicate = q => !q.IsDeleted;
if (!string.IsNullOrWhiteSpace(query.Search))
{
predicate = predicate.And(q => q.Title.Contains(query.Search));
}
Func<IQueryable<Question>, IOrderedQueryable<Question>> orderBy = null;
if (true)
{
orderBy = q => q.OrderByDescending(x => x.CreatedAt);
}
else
{
orderBy = q => q.OrderByDescending(x => x.CreatedAt);
}
var questions = await _work.GetRepository<Question>().GetPagedListAsync(
predicate: predicate,
orderBy: orderBy,
pageIndex: query.PageIndex,
pageSize: query.PageSize
);
if (!questions.Items.Any())
{
return ApiResponse.Error("未找到任何题目。", Enumerable.Empty<Question>()); // 返回空 Question 集合
}
// 直接返回 Question 实体集合
return ApiResponse.Success(result: questions);
}
catch (Exception ex)
{
return ApiResponse.Error($"获取题目列表时出现问题: {ex.Message}");
}
}
public async Task<ApiResponse> GetAsync(Guid id)
{
try
{
var question = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(predicate: q => q.Id == id && !q.IsDeleted);
if (question == null)
{
return ApiResponse.Error($"找不到 ID 为 {id} 的题目。");
}
// 直接返回 Question 实体
return ApiResponse.Success(result: question);
}
catch (Exception ex)
{
return ApiResponse.Error($"获取题目时发生错误: {ex.Message}");
}
}
public async Task<ApiResponse> UpdateAsync(Question model)
{
try
{
var existingQuestion = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(predicate: q => q.Id == model.Id && !q.IsDeleted);
if (existingQuestion == null)
{
return ApiResponse.Error($"找不到 ID 为 {model.Id} 的题目,无法更新。");
}
// 检查更新后的题目文本是否与现有其他题目重复
var duplicateCheck = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
predicate: q => q.Id != model.Id && q.Title == model.Title && !q.IsDeleted
);
if (duplicateCheck != null)
{
return ApiResponse.Error($"题目文本 '{model.Title}' 已被其他题目占用,请修改。");
}
// 手动复制属性或使用 AutoMapper (如果保留了 _mapper 字段)
// 如果选择手动复制,请确保复制所有需要更新的属性
existingQuestion = model;
_work.GetRepository<Question>().Update(existingQuestion);
await _work.SaveChangesAsync();
// 直接返回更新后的 Question 实体
return ApiResponse.Success("题目更新成功。", existingQuestion);
}
catch (Exception ex)
{
return ApiResponse.Error($"更新题目失败: {ex.Message}");
}
}
}
// PredicateBuilder 保持不变,如果你没有使用 LinqKit这部分是必需的
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
var invokedExpr = Expression.Invoke(second, first.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(first.Body, invokedExpr), first.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
var invokedExpr = Expression.Invoke(second, first.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(first.Body, invokedExpr), first.Parameters);
}
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
}
}