~/Models/BlogPost.cs:
public class BlogPost
{
public int BlogPostID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime LastEdited { get; set; }
public ApplicationUser Author { get; set; }
}
~/Models/ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
public string Nickname;
public int Age;
}
~/Controllers/BlogController.cs:
private readonly ApplicationDbContext _context;
public async Task<IActionResult> Edit(int id, [Bind("BlogPostID, Title, Content")] BlogPost post)
{
var author = _context.BlogPosts
.Include(entry => entry.Author)
.AsNoTracking()
.FirstOrDefaultAsync(entry => entry.BlogPostId == id)
.Result
.Author;
// Users should only be able to edit their own posts
if(author.Id != User.Id)
{
return RedirectToAction(nameof(Index));
}
// Do some operations like updating when the post was edited
post.LastEdited = DateTime.Now;
_context.Update(post);
await _context.SaveChangesAsync();
}
// But what if we have abstracted retrieving posts to a service?
~/Services/BlogPostService.cs:
private readonly ApplicationDbContext _context;
public async Task<BlogPost> GetBlogPostAsync(int id)
{
var post = _context.BlogPosts
.Include(entry => entry.Author)
.FirstOrDefaultAsync(entry => entry.BlogPostId == id)
.Result;
// Verify that the post exists etc. here
return post;
}
// Then we get the following problem in the controller:
~/Controllers/BlogController.cs:
private readonly IBlogPostService _blogPostService;
public async Task<IActionResult> Edit(int id, [Bind("BlogPostID, Title, Content")] BlogPost post)
{
// This throws an error because there are now two instances tracking the same Primary Key { BlogPostID }
var author = _blogPostService.GetBlogPostAsync(id).Result.Author;
// Users should only be able to edit their own posts
if(author.Id != User.Id)
{
return RedirectToAction(nameof(Index));
}
// Do some operations like updating when the post was edited
post.LastEdited = DateTime.Now;
_context.Update(post);
await _context.SaveChangesAsync();
}
// If I modify the service class to use .AsNoTracking() when grabbing the post it could cause issues in situations where I DO want to track the changes.
// I could always have a function GetBlogPostAsyncAsNoTracking(int id); but that seems excessive and would cause redundant code. Furthermore, using an optional boolean argument to the GetBlogPostAsync(int id, bool? AsNoTracking); could work, but seems like a bad idea as well.
Comments