::: moniker range=">= aspnetcore-2.1" Right click on a red squiggly line > **Quick Actions and Refactorings** on the `[Column]` atribute and select `using System.ComponentModel.DataAnnotations.Schema;` The `[Column(TypeName = "decimal(18, 2)")]` data annotation is required so Entity Framework Core can correctly map `Price` to currency in the database. For more information, see [Data Types](/ef/core/modeling/relational/data-types). The completed model: [!code-csharp[Main](~/tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie21/Models/MovieDateFixed.cs?name=snippet_1)] ::: moniker-end We'll cover [DataAnnotations](/aspnet/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-6) in the next tutorial. The [Display](/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.metadata.displaymetadata) attribute specifies what to display for the name of a field (in this case "Release Date" instead of "ReleaseDate"). The [DataType](/dotnet/api/microsoft.aspnetcore.mvc.dataannotations.internal.datatypeattributeadapter) attribute specifies the type of the data (Date), so the time information stored in the field isn't displayed. Browse to Pages/Movies and hover over an **Edit** link to see the target URL. ![Browser window with mouse over the Edit link and a link Url of http://localhost:1234/Movies/Edit/5 is shown](~/tutorials/razor-pages/da1/edit7.png) The **Edit**, **Details**, and **Delete** links are generated by the [Anchor Tag Helper](xref:mvc/views/tag-helpers/builtin-th/anchor-tag-helper) in the *Pages/Movies/Index.cshtml* file. [!code-cshtml[](~/tutorials/razor-pages/razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Index.cshtml?highlight=16-18&range=32-)] [Tag Helpers](xref:mvc/views/tag-helpers/intro) enable server-side code to participate in creating and rendering HTML elements in Razor files. In the preceding code, the `AnchorTagHelper` dynamically generates the HTML `href` attribute value from the Razor Page (the route is relative), the `asp-page`, and the route id (`asp-route-id`). See [URL generation for Pages](xref:razor-pages/index#url-generation-for-pages) for more information. Use **View Source** from your favorite browser to examine the generated markup. A portion of the generated HTML is shown below: ```html Edit | Details | Delete ``` The dynamically-generated links pass the movie ID with a query string (for example, `http://localhost:5000/Movies/Details?id=2`). Update the Edit, Details, and Delete Razor Pages to use the "{id:int}" route template. Change the page directive for each of these pages from `@page` to `@page "{id:int}"`. Run the app and then view source. The generated HTML adds the ID to the path portion of the URL: ```html Edit | Details | Delete ``` A request to the page with the "{id:int}" route template that does **not** include the integer will return an HTTP 404 (not found) error. For example, `http://localhost:5000/Movies/Details` will return a 404 error. To make the ID optional, append `?` to the route constraint: ```cshtml @page "{id:int?}" ``` ::: moniker range="= aspnetcore-2.0" ### Update concurrency exception handling Update the `OnPostAsync` method in the *Pages/Movies/Edit.cshtml.cs* file. The following highlighted code shows the changes: [!code-csharp[](~/tutorials/razor-pages/razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Edit.cshtml.cs?name=snippet1&highlight=16-23)] The previous code only detects concurrency exceptions when the first concurrent client deletes the movie, and the second concurrent client posts changes to the movie. To test the `catch` block: * Set a breakpoint on `catch (DbUpdateConcurrencyException)` * Edit a movie. * In another browser window, select the **Delete** link for the same movie, and then delete the movie. * In the previous browser window, post changes to the movie. Production code would generally detect concurrency conflicts when two or more clients concurrently updated a record. See [Handle concurrency conflicts](xref:data/ef-rp/concurrency) for more information. ::: moniker-end ### Posting and binding review Examine the *Pages/Movies/Edit.cshtml.cs* file: ::: moniker range="= aspnetcore-2.0" [!code-csharp[](~/tutorials/razor-pages/razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Edit.cshtml.cs?name=snippet2)] ::: moniker-end ::: moniker range=">= aspnetcore-2.1" [!code-csharp[](~/tutorials/razor-pages/razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Edit21.cshtml.cs?name=snippet2)] ::: moniker-end When an HTTP GET request is made to the Movies/Edit page (for example, `http://localhost:5000/Movies/Edit/2`): * The `OnGetAsync` method fetches the movie from the database and returns the `Page` method. * The `Page` method renders the *Pages/Movies/Edit.cshtml* Razor Page. The *Pages/Movies/Edit.cshtml* file contains the model directive (`@model RazorPagesMovie.Pages.Movies.EditModel`), which makes the movie model available on the page. * The Edit form is displayed with the values from the movie. When the Movies/Edit page is posted: * The form values on the page are bound to the `Movie` property. The `[BindProperty]` attribute enables [Model binding](xref:mvc/models/model-binding). ```csharp [BindProperty] public Movie Movie { get; set; } ``` * If there are errors in the model state (for example, `ReleaseDate` cannot be converted to a date), the form is posted again with the submitted values. * If there are no model errors, the movie is saved. The HTTP GET methods in the Index, Create, and Delete Razor pages follow a similar pattern. The HTTP POST `OnPostAsync` method in the Create Razor Page follows a similar pattern to the `OnPostAsync` method in the Edit Razor Page. Search is added in the next tutorial.