We replaced the
FindAsync(ID) call with a LINQ type syntax statement. The
FirstOrDefaultAsync() method returns a single record that matches the lambda expression in the parameter. We are not limited to ID in this regard and could as easily search by Name.
We added some code to search and filter. A button posts back a form with a search string. The SearchString uses the
[BindProperty] annotation with special qualifier of
SupportsGet. This tells the
OnGetAsync() method that a SearchString may exist when the page is ready to load.
OnGetAsync() uses a conditional statement to add the
SearchString value to a new LINQ query. The var countries is first assigned a LINQ statement that returns all rows by default. If a
SearchString is present, the query is modified to include a where clause that filters only by Name. The LINQ query is not turned into a SQL database query until the
ToListAsync() method is called. This is an important concept in LINQ. Any number of modifications to a query are allowed until the final evaluation to a list.
We added sorting using a
<select> tag to hold the column names in a series of
<option> tags. We added an
onChange() event that posts the form each time a change is made.
We also limited our searches by continent using a select list. LINQ is used to gather all continents while sorting then alphabetically. The result of the query is assigned to a
SelectList component during
OnGetAsync(). The component added the All option as part of the markup. Multiple modifiers allows us to filter by a continent and include a country name search string.
We replaced the Continent
<input> text box with a
SelectList. This has the added value of ensuring that only a valid Continent is selected. The
<select> uses the
asp-for attribute the same way
<input> does. It has an additional
asp-items attribute for the source of the dropdown list.
LINQ can take advantage of navigational properties coded into the entity models. This is a C# way of supporting one to many and many to many data relationships. We added lines to our models so that Entity Framework knows that the two tables are related. Continents have a collection of Countries and Countries have a related Continent.
We enhanced our Continent Detail page by including a list of related Countries. The LINQ record retrieval statement for a single Continent added the
Include() chain statement. EF loads all related Countries each time it loads a
AsNoTracking() is a hint that says we will not be updating the
Countries. This improves performance. Markup was added to the page to display the list of member Countries.
We used inheritance to make a new data model called CountryStat.cs. It has an additional member called Density. We retrieved a single
CountryStat object instead of a Country and added a new field in the page markup.
Open the file Pages/Continents/Detail.cshtml.cs to see the new LINQ like record retrieval syntax.
Open the file Pages/Continents/Index.cshtml.cs to see how search and filtering were implemented.
Open the file Pages/Continents/Edit.cshtml.cs to see how the select list was added to the Edit experience.
Open the files Models/Continent.cs and Models/Country.cs to see navigational properties added to models. Also look at Models/CountryStat.cs to see the use of model inheritance and calculated fields.
Open the file Pages/Countries/Detail.cshtml.cs again to see related record retrieval.