The title somehow looks like random words, picked from a hat at one of those college games we are not supposed to talk about. Anyway, at the second reading it hopefully becomes a bit clearer. And it is simply the “magic” of creating 2 C# classes in visual studio and transferring them to tables in a database with the magic of Entity Framework. Then, with ASP, being able to access the database with the 2 tables and making simple CRUD (Create, Read, Update, Delete) actions. This is how the R in CRUD looks like:
As mentioned, there are 2 main classes in the application – Blog.cs and Post.cs and these have a relation 1-to-many between each other:
As far as the code is mainly generated from the scaffold features of Visual Studio, I will show only the PostController.cs and the \Posts\Details.cshtml here. The rest is in GitHub and in the video.
PostController.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; using EFGetStarted.Models; namespace EFGetStarted.Controllers { public class PostsController : Controller { private readonly BloggingContext _context; public PostsController(BloggingContext context) { _context = context; } // GET: Posts public async Task Index() { var bloggingContext = _context.Posts.Include(p => p.Blog); return View(await bloggingContext.ToListAsync()); } // GET: Posts/Details/5 public async Task Details(int? id) { if (id == null) { return NotFound(); } var post = await _context.Posts .Include(p => p.Blog) .FirstOrDefaultAsync(m => m.PostId == id); if (post == null) { return NotFound(); } return View(post); } // GET: Posts/Create public IActionResult Create() { ViewData["BlogId"] = new SelectList(_context.Blogs, "BlogId", "BlogId"); return View(); } // POST: Posts/Create // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public async Task Create([Bind("PostId,Title,Content,BlogId")] Post post) { if (ModelState.IsValid) { _context.Add(post); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } ViewData["BlogId"] = new SelectList(_context.Blogs, "BlogId", "BlogId", post.BlogId); return View(post); } // GET: Posts/Edit/5 public async Task Edit(int? id) { if (id == null) { return NotFound(); } var post = await _context.Posts.FindAsync(id); if (post == null) { return NotFound(); } ViewData["BlogId"] = new SelectList(_context.Blogs, "BlogId", "BlogId", post.BlogId); return View(post); } // POST: Posts/Edit/5 // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public async Task Edit(int id, [Bind("PostId,Title,Content,BlogId")] Post post) { if (id != post.PostId) { return NotFound(); } if (ModelState.IsValid) { try { _context.Update(post); await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!PostExists(post.PostId)) { return NotFound(); } else { throw; } } return RedirectToAction(nameof(Index)); } ViewData["BlogId"] = new SelectList(_context.Blogs, "BlogId", "BlogId", post.BlogId); return View(post); } // GET: Posts/Delete/5 public async Task Delete(int? id) { if (id == null) { return NotFound(); } var post = await _context.Posts .Include(p => p.Blog) .FirstOrDefaultAsync(m => m.PostId == id); if (post == null) { return NotFound(); } return View(post); } // POST: Posts/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public async Task DeleteConfirmed(int id) { var post = await _context.Posts.FindAsync(id); _context.Posts.Remove(post); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } private bool PostExists(int id) { return _context.Posts.Any(e => e.PostId == id); } } } |
\Posts\Details.cshtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
@model EFGetStarted.Models.Post @{ ViewData["Title"] = "Details"; } <h2>Details</h2> <div> <h4>Post</h4> <hr> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.Title) </dt> <dd> @Html.DisplayFor(model => model.Title) </dd> <dt> @Html.DisplayNameFor(model => model.Content) </dt> <dd> @Html.DisplayFor(model => model.Content) </dd> <dt> @Html.DisplayNameFor(model => model.Blog) </dt> <dd> @Html.DisplayFor(model => model.Blog.BlogId) </dd> </dl> </div> <div> <a asp-action="Edit" asp-route-id="@Model.PostId">Edit</a> | <a asp-action="Index">Back to List</a> </div> |
The video:
The GitHub code:
https://github.com/Vitosh/ASP/tree/master/EFGetStarted
The Original Microsoft.com tutorial:
https://docs.microsoft.com/en-us/ef/core/get-started/aspnetcore/new-db?tabs=visual-studio