댓글기능을 구현하는 과정, 자세히는
public List<CommentModel> Comments { get; set; } = new List<CommentModel>();
라는 속성을 가진 PostModel의 Comments 속성에 데이터를 추가하는 과정에서 문제가 발생하였다.
평소대로
public async Task<IActionResult> Details(int id, string Comment)
{
if (ModelState.IsValid)
{
var commentModel = new CommentModel
{
Author = HttpContext.Session.GetString("UserId"),
Contents = Comment,
Date = DateTime.Now,
PostId = id
};
_context.Add(commentModel);
var postModel = await _context.PostModel
.FirstOrDefaultAsync(m => m.Id == id);
postModel.Comments.Add(commentModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Details), new { id = commentModel.PostId });
}
return View();
}
POST요청으로 전송된 데이터의 유효성을 검사하고 View에서 입력된 데이터 집어넣고 뷰에서 받아온 Id에 해당하는 게시물 불러오고 해당 게시물의 Comments에 데이터를 추가하고 DB를 저장하였다.
그러나
내가 입력한 댓글이 게시물에 보이지 않았다.
CommentModel 데이터베이스에는 데이터가 정상적으로 담긴것으로 보아 댓글자체가 저장되지 않는건 아닌듯 했다.
이를 해결하기 위해 몇가지의 가설을 세웠다.
1. 데이터베이스에 변경사항이 적용이 되지 않았다.
2. PostModel과 CommentModel을 동시에 로드하는데 _context.PostModel.FirstOrDefaultAsync 메서드 외의 방법이 존재한다.
3. View에서의 출력방식에 문제가 있다.
4. List자료형의 모델 속성은 데이터 추가가 불가능하다.
5. List자료형에 데이터를 추가하는 메서드 자체가 실행이 안된다.
6. postModel이 null이다.
먼저 6번 가설을 검증하기 위해 코드를 다음과 같이 수정해보았다.
public async Task<IActionResult> Details(int id, string Comment)
{
if (ModelState.IsValid)
{
var commentModel = new CommentModel
{
Author = HttpContext.Session.GetString("UserId"),
Contents = Comment,
Date = DateTime.Now,
PostId = id
};
_context.Add(commentModel);
var postModel = await _context.PostModel
.FirstOrDefaultAsync(m => m.Id == id);
if (postModel == null)
{
Console.WriteLine("513sd4fwefsd3z53fas4dz45szdf453f5");
}
else
{
Console.WriteLine("879465132648794651648796513486651");
Console.WriteLine(postModel.Title);
}
postModel.Comments.Add(commentModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Details), new { id = commentModel.PostId });
}
return View();
}
결과는 다음과 같았다.


게시글의 제목과 8....1이 출력되는 것을 보아 postModel이 null은 아니다.
다음으로 5번 가설을 검증하기 위해 코드를 다음과 같이 수정하였다.
public async Task<IActionResult> Details(int id, string Comment)
{
if (ModelState.IsValid)
{
var commentModel = new CommentModel
{
Author = HttpContext.Session.GetString("UserId"),
Contents = Comment,
Date = DateTime.Now,
PostId = id
};
_context.Add(commentModel);
var postModel = await _context.PostModel
.FirstOrDefaultAsync(m => m.Id == id);
postModel.Comments.Add(commentModel);
foreach(var comment in postModel.Comments)
{
Console.WriteLine(comment.Contents);
}
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Details), new { id = commentModel.PostId });
}
return View();
}
실행결과는 다음과 같다.


postModel의 Comments 속성에 데이터는 정상적으로 저장된다.
이 실험으로 3, 4, 5번의 가설은 거짓이된다. 댓글을 출력하는 View코드는 실험에 사용한 코드와 같았고, List자료형에 데이터가 정상적으로 저장되었기 때문이다.
이제 남은 가설은 1, 2번이다.
먼저 1번 가설을 검증하기 위해 코드를 다음과 같이 수정하였다.
public async Task<IActionResult> Details(int id, string Comment)
{
if (ModelState.IsValid)
{
var commentModel = new CommentModel
{
Author = HttpContext.Session.GetString("UserId"),
Contents = Comment,
Date = DateTime.Now,
PostId = id
};
_context.Add(commentModel);
var postModel = await _context.PostModel
.FirstOrDefaultAsync(m => m.Id == id);
postModel.Comments.Add(commentModel);
await _context.SaveChangesAsync();
foreach(var comment in postModel.Comments)
{
Console.WriteLine(comment.Contents);
}
return RedirectToAction(nameof(Details), new { id = commentModel.PostId });
}
return View();
}
만약 저장한 댓글이 데이터베이스에 적용이되지 않는다면 Console.WriteLine(comment.Contents); 실행 후 아무것도 출력되지 않거나, 오류가 날것이다.
실험 결과


내가 작성한 댓글인 123123이 콘솔창에 나타났다.
이로써 1번 가설은 틀린것이 증명되었다.
마지막으로 2번이 남았다. 이 가설조차 거짓이면 정말 이 문제를 해결할 길이 보이지 않았을 것이다.
2번 가설을 증명하기 위해 List 자료형을 지닌 속성을 불러오는 방법이 따로 있는지 검색해보았다.
검색결과..
https://stackoverflow.com/questions/26661771/what-does-include-do-in-linq
What does Include() do in LINQ?
I tried to do a lot of research but I'm more of a db guy - so even the explanation in the MSDN doesn't make any sense to me. Can anyone please explain, and provide some examples on what Include()
stackoverflow.com
이 문제를 해결할 메서드가 존재했었다. 정확히 말하면 하나의 모델 엔터티와 관련된 다른 엔터티를 함께 로드하는 메서드가 존재했다.
즉, var postModel = await _context.PostModel.Include(p => p.Comments).FirstOrDefaultAsync(m => m.Id == id); 가 아닌
var postModel = await _context.PostModel.FirstOrDefaultAsync(m => m.Id == id); 로 엔터티를 로드하면, Postmodel과 Comments 엔터티가 로드되어 postModel.Comments를사용하면 Comments 엔터티 즉, 복수의 CommentModel 엔터티에 접근할 수 있는 것이다.
Include 메서드를 사용하지 않고 PostModel 엔터티만 로드했을 땐 Comments 엔터티(테이블)는 로드하지 않았으므로 Comments에 저장된 다른 데이터들에 대한 접근이 불가능했던 것이다.
따라서 내가 수정한 최종코드는 다음과 같다.
public async Task<IActionResult> Details(int id, string Comment)
{
if (ModelState.IsValid)
{
var commentModel = new CommentModel
{
Author = HttpContext.Session.GetString("UserId"),
Contents = Comment,
Date = DateTime.Now,
PostId = id
};
_context.Add(commentModel);
var postModel = await _context.PostModel
.Include(p => p.Comments)
.FirstOrDefaultAsync(m => m.Id == id);
postModel.Comments.Add(commentModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Details), new { id = commentModel.PostId });
}
return View();
}'기타' 카테고리의 다른 글
| [ASP.NET Core/APOD] 댓글 저장 방식에 대한 고찰 (0) | 2023.04.10 |
|---|---|
| [ASP.NET Core/APOD] 댓글 기능 구현 (0) | 2023.04.08 |
| [ASP.NET Core/Devroup] ForeignKey: 외래키에 대해 (0) | 2023.03.31 |
| [ASP.NET Core/Devroup] TempData, ViewData에 대한 고찰 (0) | 2023.03.28 |
| [ASP.NET Core/Devroup] HttpContext.Session을 _Layout에서 사용하기 위한 방법 (0) | 2023.03.26 |