Presentation is loading. Please wait.

Presentation is loading. Please wait.

Further exploring database operations in MVC Jim Warren, COMPSCI 280 S2 2014 Enterprise Software Development.

Similar presentations


Presentation on theme: "Further exploring database operations in MVC Jim Warren, COMPSCI 280 S2 2014 Enterprise Software Development."— Presentation transcript:

1 Further exploring database operations in MVC Jim Warren, jim@cs.auckland.ac.nz COMPSCI 280 S2 2014 Enterprise Software Development

2 Today’s learning objectives  To be able to query through a variety of approaches including sending SQL directly to the DBMS and via LINQ  To be able to write more advanced queries in the MVC context, including joining tables and mapping the result to the View  To be able to update the database from the MVC context COMPSCI 2802

3 Last lecture…  We introduced Language Integrated Query (LINQ)  In this case the return value is a collection of objects of a class we’ve already defined in the Model  Because we had said: public DbSet Employees { get; set; } and had defined the Employee class with property names exactly aligned to the columns of the DBMS table  And in the VIEW we had said: @model IEnumerable Handout 03COMPSCI 2803 using (EmployeesContext db = new EmployeesContext()) { var emp = from e in db.Employees where e.DateOfBirth.Year < 1975 select e; return View(emp.ToList()); }

4 Dealing with a Join  But what if we want to present the user with the result of a Join on two (or more) tables?  Say that there’s a ‘role’ table which maps ‘employee’ rows by their primary key IDnum to one or more job roles  And I want to present the user with the meaningful fields from SELECT * FROM employee,role WHERE employee.IDnum=role.Idnum; Handout 03COMPSCI 2804 employee role

5 Extending the model  In your.cs file in the Models directory  Add the new DbSet to the DbContext  And add a class definition matching the new table  Fine so far… but what’s the class of the Join result? Handout 03COMPSCI 2805 public class EmployeesContext : DbContext { public EmployeesContext() : base("MySqlConnection") { } public DbSet Employees { get; set; } public DbSet Roles { get; set; } } [Table("role")] public class EmpRole { [Key] public int jobnum { get; set; } public int IDnum { get; set; } public string Role { get; set; } }

6 The Join  In HomeController.cs we can use a LINQ query  Back in the model, we need to define this new class Handout 03COMPSCI 2806 var ourEmployees = from e in db.Employees from r in db.Roles where e.IDnum == r.IDnum orderby e.Surname select new EmpforGrid { IDnum = e.IDnum, Surname = e.Surname, GivenNames = e.GivenNames, YearOfBirth = e.DateOfBirth.Year, Role = r.Role}; public class EmpforGrid { public int IDnum {get; set;} public string Surname {get; set;} public string GivenNames {get; set;} public int YearOfBirth { get; set;} public string Role { get; set;} } Also perfectly good, and better use of the LINQ language, would be to replace the 2 nd FROM and the WHERE with: join r in db.Roles on e.IDnum equals r.IDnum

7 The View  In Index.cshtml (under Views/Home)  We define the model for the view as an enumerable collection of instances of the new class: @model IEnumerable  And we define the WebGrid itself Handout 03COMPSCI 2807 @{ ViewBag.Title = "People"; WebGrid grid = new WebGrid(Model); } People @grid.GetHtml(columns: grid.Columns( grid.Column("IDnum","Employee ID"), grid.Column("Surname","Last Name"), grid.Column("GivenNames","Given Names"), grid.Column("YearOfBirth","Birth Year"), grid.Column("Role","Role")))

8 The result Handout 03COMPSCI 2808

9 ‘Native’ SQL  You can also send ‘native’ SQL direct to the DBMS  Create a string, not interpreted as a query by VS  And send it to the database context with the SqlQuery method  Show the join, and a count(*) Handout 03COMPSCI 2809 string the_name = "Tom"; nativeSQLQuery = String.Format("SELECT COUNT(*) FROM employee WHERE GivenNames='{0}'",the_name); var cnt = db.Database.SqlQuery (nativeSQLQuery); ViewBag.empcnt = "Count=" + cnt.First(); nativeSQLQuery = "SELECT * FROM employee,role WHERE employee.IDnum=role.IDnum;"; var empr = db.Database.SqlQuery (nativeSQLQuery); return View(empr.ToList()); The SqlQuery returns a ‘generic’ class that takes a type parameter (I’m counting here, so int is good) I can just put anything in ViewBag and it’ll be available in the View. Since I was counting I only want the first (and only) item in the collection that was returned Since I’ve typed this as EmpforGrid, I can use it as the Model to pass to my View for the WebGrid

10 The result  Easily fixed by updating the SQL: nativeSQLQuery = "SELECT *,Year(employee.DateOfBirth) as YearOfBirth FROM employee,role WHERE employee.IDnum=role.IDnum;"; Handout 03COMPSCI 28010 Oh, oops! EmpforGrid has a YearOfBirth not a DateofBirth (as in the employee table). It forgave me for leaving it out of the SqlQuery result and put in a ‘convenient’ default Note I’m using the SQL syntax Year() for the conversion, not the C# syntax which is to invoke the.Year method on the DateTime object

11 What about the rest of the CRUD?!  CRUD  Create, Read, Update, Delete  A CRUD matrix can be a useful specification for the scope of programming tasks  E.g. to describe the ‘life cycle’ of each entity in a system; e.g. a hotel reservation  On some screen (e.g. ‘booking’) it is created (SQL INSERT, not CREATE like making a new table)  There may be a screen to update it (e.g. ‘change booking’) which probably also reads the current value (‘R’ of CRUD, SQL SELECT)  And there will be one or more ways to delete it (e.g. from a cancellation action on the change booking screen or a dedicated cancellation screen, and also once the person has checked in) – then again, you might not actually delete in a SQL sense, but UPDATE it to cancelled or utilised status Handout 03COMPSCI 28011

12 Where we want to go Handout 03COMPSCI 28012

13 And when we click an Edit link… Handout 03COMPSCI 28013

14 The UPDATE  Native SQL version  Given that I have a reference to an object emp of class Employee with updated values: Handout 03COMPSCI 28014 using (EmployeesContext db = new EmployeesContext()) { string sql=String.Format( "UPDATE employee SET Surname='{0}',GivenNames='{1}',"+ "DateOfBirth='{2:yyyy-MM-dd}' WHERE IDnum={3}", emp.Surname,emp.GivenNames,emp.DateOfBirth,emp.IDnum); db.Database.ExecuteSqlCommand(sql);... } Here we’re just building the text of a SQL command with the help of String.Format to plug in the parameters from our C# code at the curly braces (note the 3 rd parameter - #2 counting from 0! – is formatted so MySQL recognises the date literal Then we just.ExecuteSqlCommand (as compared doing. SqlQuery) on the database context to tell MySQL to have at it Re-establish the database connection

15 The UPDATE v2  Entity Framework* version  Now assuming a bit more about emp … not just that it’s an object of class Employee, but that it’s already ‘attached’ to the database context.  As it turns out, this will be a correct assumption once we put this code into the appropriate part of the MVC application * Entity Framework (EF) is an object-relational mapper that enables.NET developers to work with relational data using domain-specific objects – http://msdn.microsoft.com/en-us/data/ef.aspx– http://msdn.microsoft.com/en-us/data/ef.aspx Handout 03COMPSCI 28015 using (EmployeesContext db = new EmployeesContext()){ db.Entry(emp).State = EntityState.Modified; db.SaveChanges();... } The 'State' property determines what's done by the SaveChanges method (modified entities are updated)

16 Putting the update in the MVC context  Making an Edit controller  In HomeController.cs we need a new method to ‘catch’ the invocation of the Edit screen Handout 03COMPSCI 28016 public ActionResult Edit(int id) { ViewBag.Message = String.Format( "Your are editing the record for employee ID #{0}.",id); using (EmployeesContext db = new EmployeesContext()) { Employee emp = db.Employees.Find(id); if (emp == null) return HttpNotFound(); return View(emp); }.Find looks up a record from the dbSet based on its primary key (IDnum was set up as such in MySQL and then this was conveyed to the MVC application by the [Key] decorator in the Model If we picked it off the WebGrid table that we ourselves define it really should be found, but good to handle anyway (e.g. user might edit the URL string, or somebody might’ve deleted it since the user last refreshed their browser screen) We’ll set up the invocation such that the IDnum of the selected record is passed to this handler

17 And we need a second version…  In HomeController.cs we need a second signature for the method  This version catches the Edit screen when it’s being returned to us filled out / updated by the user Handout 03COMPSCI 28017 [HttpPost] public ActionResult Edit(Employee emp) { if (ModelState.IsValid) { using (EmployeesContext db = new EmployeesContext()) { db.Entry(emp).State = EntityState.Modified; db.SaveChanges(); } return RedirectToAction("Index"); } return View(emp); } The Edit screen will post back a reference to the whole updated Employee object, emp. If it’s valid (more on that later!) then we save the update to the database If the data was valid, the edit is done so redirect back to the home page; otherwise (there’s some invalid data on the form), present the form to the user again The [HttpPost] decorator signals that this is the one to receive a completed HTML form (the previous one could’ve been annotated as [HttpGet])

18 Invoking the edit controller  Putting an ActionLink into the WebGrid  To define the column with the Edit link on each employee: grid.Column(header: "Edit", format: (item) => Html.ActionLink("Edit", "Edit", new { id=item.IDnum }))  OK, a bit of cryptic Razor syntax here, but note  We’re creating an ActionLink (labelled “Edit” and that invokes the Edit handler in our controller)  It’s per ‘item’ in the WebGrid (one link for each employee) – ‘item’ is just a magic keyword to indicate the entity on the current row  The => is a ‘lambda expression’ (more on that later… it’s a function as a parameter)  We assign the.IDnum of the current item (i.e. it’s primary key) to ‘id’ – which is the parameter expected by our controller code! Handout 03COMPSCI 28018

19 Inspecting the HTML  All that Razor boiled down to a hyperlink calling /Home/Edit/2 (the Home controller, looking for the Edit method with a parameter value of 2) Handout 03COMPSCI 28019

20 Where we’re up to  We’ve seen that we can interact with our DBMS by sending it native SQL or using C#/.NET language-embedded syntax (LINQ and Entity Framework)  And we can add and invoke additional handlers in our controller (e.g. for an Edit/Update function)  FYI: a battery of LINQ examples: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b  Now…  Work the second labsheet (if you haven’t already)  Get seriously into Assignment 2  Next lecture we’ll look at creating the HTML form to get interactive input from the user for the Edit / Update Handout 03COMPSCI 28020


Download ppt "Further exploring database operations in MVC Jim Warren, COMPSCI 280 S2 2014 Enterprise Software Development."

Similar presentations


Ads by Google