CategoryController.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System.Diagnostics;
  2. using bitforum.Models;
  3. using bitforum.Models.Page.Faq;
  4. using bitforum.Models.Views;
  5. using Microsoft.AspNetCore.Authorization;
  6. using Microsoft.AspNetCore.Mvc;
  7. using Microsoft.EntityFrameworkCore;
  8. namespace bitforum.Controllers.Page
  9. {
  10. [Authorize]
  11. [Route("Page")]
  12. public class CategoryController : Controller
  13. {
  14. private readonly ILogger<CategoryController> _logger;
  15. private readonly DefaultDbContext _db;
  16. private readonly string _ViewPath = "~/Views/Page/Faq/Index.cshtml";
  17. public CategoryController(ILogger<CategoryController> logger, DefaultDbContext db)
  18. {
  19. _logger = logger;
  20. _db = db;
  21. }
  22. [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
  23. public IActionResult Error()
  24. {
  25. return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
  26. }
  27. [HttpGet("Faq")]
  28. public IActionResult Index()
  29. {
  30. var viewModel = new FaqCategoryViewModel
  31. {
  32. FaqCategories = _db.FaqCategory .Include(c => c.FaqItem).OrderByDescending(c => c.Order).ToList()
  33. };
  34. ViewBag.ItemCounts = viewModel.FaqCategories.ToDictionary(
  35. category => category.ID,
  36. category => category.FaqItem.Count
  37. );
  38. return View(_ViewPath, viewModel);
  39. }
  40. [HttpPost]
  41. public async Task<IActionResult> Save(FaqCategoryViewModel request)
  42. {
  43. using var transaction = await _db.Database.BeginTransactionAsync();
  44. try
  45. {
  46. if (request.FaqCategories == null || !request.FaqCategories.Any())
  47. {
  48. throw new Exception("저장할 데이터가 없습니다.");
  49. }
  50. if (!ModelState.IsValid)
  51. {
  52. throw new Exception("유효성 검사에 실패하였습니다.");
  53. }
  54. var requestIds = request.FaqCategories.Select(x => x.ID).ToList(); // 요청 데이터의 ID 목록
  55. var existingIds = await _db.FaqCategory.Select(c => c.ID).ToListAsync(); // 데이터베이스에 존재하는 ID 목록
  56. var idsToDelete = existingIds.Except(requestIds).ToList(); // 삭제 대상 ID: 요청 데이터에 없는 항목
  57. // 삭제 대상 항목 제거
  58. if (idsToDelete.Any())
  59. {
  60. var rr = await _db.FaqCategory.Where(c => idsToDelete.Contains(c.ID)).ToListAsync();
  61. _db.FaqCategory.RemoveRange(
  62. rr
  63. );
  64. }
  65. foreach (var row in request.FaqCategories)
  66. {
  67. // 중복 확인
  68. if (await _db.FaqCategory.AnyAsync(c => c.Code == row.Code && c.ID != row.ID))
  69. {
  70. throw new Exception($"이미 존재하는 Code 주소입니다: {row.Code}");
  71. }
  72. if (row.ID == 0)
  73. {
  74. row.UpdatedAt = null;
  75. row.CreatedAt = DateTime.Now;
  76. await _db.FaqCategory.AddAsync(row);
  77. }
  78. else
  79. {
  80. var existing = await _db.FaqCategory.FirstOrDefaultAsync(c => c.ID == row.ID);
  81. if (existing == null)
  82. {
  83. throw new Exception($"ID {row.ID}에 해당하는 데이터가 없습니다.");
  84. }
  85. // 기존 엔터티 업데이트
  86. existing.Code = row.Code;
  87. existing.Subject = row.Subject;
  88. existing.Order = row.Order;
  89. existing.IsActive = row.IsActive;
  90. existing.UpdatedAt = DateTime.Now;
  91. _db.FaqCategory.Update(existing);
  92. }
  93. }
  94. int affectedRows = await _db.SaveChangesAsync();
  95. if (affectedRows <= 0)
  96. {
  97. throw new Exception("FAQ 저장 중 오류가 발생했습니다.");
  98. }
  99. await transaction.CommitAsync();
  100. string message = "FAQ 분류가 정상적으로 저장되었습니다.";
  101. TempData["SuccessMessage"] = message;
  102. _logger.LogInformation(message);
  103. return RedirectToAction("Index");
  104. }
  105. catch (DbUpdateException ex)
  106. {
  107. await transaction.RollbackAsync();
  108. _logger.LogError(ex, ex.InnerException?.Message ?? ex.Message);
  109. throw new Exception("데이터 저장 중 오류 발생: " + (ex.InnerException?.Message ?? ex.Message));
  110. }
  111. catch (Exception e)
  112. {
  113. await transaction.RollbackAsync();
  114. _logger.LogError(e, e.Message);
  115. TempData["ErrorMessages"] = e.Message;
  116. return View(_ViewPath, request);
  117. }
  118. }
  119. }
  120. }