天天看點

建立ASP.NET Core MVC應用程式(5)-添加查詢功能 & 新字段

本文将實作通過Name查詢使用者資訊。

首先更新<code>GetAll</code>方法以啟用查詢:

第一行的LINQ查詢僅僅在這裡作了定義,并沒有在這裡實際操作資料庫。

LINQ查詢在被定義或者通過調用類似于<code>Where</code>、<code>Contains</code>、<code>OrderBy</code>的方法進行修改的時候不會執行。相反的,查詢會延遲執行,比如在<code>ToListAsync</code>方法被調用之後。

<code>Contains</code>方法會在資料庫中運作,而不是上面的C#代碼,在資料庫中,<code>Contains</code>會被映射成不區分大小寫的SQL<code>LIKE</code>。

由于<code>u =&gt; u.Name.Contains(searchString)</code>Lambda表達式在目前我所使用的MySQL Connector/NET版本中運作報錯(新版本好像已經修複了該問題,這裡懶得更新了),是以這裡先改成:

導航到<code>http://localhost:5000/User</code>,添加<code>?searchString=Zhu</code>查詢字元串,将過濾出指定的使用者資訊(<code>http://localhost:5000/User?searchString=Zhu</code>)。

如果你修改<code>Index</code>方法的簽名使得方法包含一個名為<code>id</code>的參數,那麼<code>id</code>參數将會比對Startup.cs檔案中設定的預設路由的可選項<code>{id?}</code>。

Rename後的方法:

現在你可以傳遞這個Name查詢條件作為路由資料(URL Segment)來代替查詢字元串(<code>http://localhost:5000/User/Index/Zhu</code>)。

然而,我們不能指望使用者每次都通過修改URL來進行查詢,我們通過添加UI來進行查詢。如果你想改變<code>Index</code>方法的簽名來測試怎樣傳遞路由綁定<code>ID</code>參數,将<code>searchString</code>參數改回來。

接着,打開Views/User/Index.cshtml檔案,添加<code>&lt;form&gt;</code>标記:

這裡HTML<code>&lt;form&gt;</code>标簽使用了Form Tag Helper,是以當你送出這個表單時,過濾字元串會被傳遞到User控制器的<code>Index</code>方法中。

這裡沒有使用你所希望的<code>[HttpPost] Index</code>重載方法,其實根本不需要該方法,因為這個方法并沒有改變這個應用的狀态,僅僅用來過濾資料。

你可以添加下面的<code>[HttpPost] Index</code>方法。

<code>notUsed</code>參數用于建立一個重載的<code>Index</code>方法。如果你添加了該方法,動作方法将會調用比對的<code>[HttpPost] Index</code>方法。

這個時候點選過濾按鈕時,會顯示如下界面:

然而,盡管你添加了<code>[HttpPost]</code>版本的<code>Index</code>方法,最終仍然存在局限性。想象你将一個指定的查詢作為書簽或者将查詢結果作為一個連結發送給你的朋友以便他們在打開時能看到同樣的過濾結果時,注意HTTP POST請求的URL和GET請求的URL(<code>http://localhost:5000/User</code>)是一樣的-在URL裡面沒有任何查詢資訊。查詢資訊是作為表單資料發送到伺服器的。

在請求體中可以看到查詢參數和XSRF反僞造标記(通過Form Tag Helper生成),由于查詢沒有修改資料,是以無需在控制器方法中驗證該标記。

為了把查詢參數從請求體中移到URL中,必須把請求指定為<code>HTTP GET</code>。

此時當你再送出時,URL将會包含具體的查詢條件。查詢将會跳轉到<code>HttpGet Index</code>方法,即使存在着<code>HttpPost Index</code>方法。

我們将通過Entity Framework Code First Migrations工具來添加一個新的字段到模型中,并将新的改變同步到資料庫中。

當你使用EF Code First自動建立一個資料庫時,Code First會添加一個表到資料庫中幫助跟蹤資料庫的資料結構是否和模型類保持同步。如果不同步,EF會抛出一個異常。

Build該應用(<code>dotnet build</code>)。可能由于我所使用的MySQL EF Core provider還不成熟,添加<code>DateTime</code>類型的字段時會報錯(新版本可能會修複該問題,這裡懶得去測試了)。

由于你添加了一個新的字段到<code>User</code>類,是以你需要更新所綁定的白名單,這樣新的屬性将會包含這内。為<code>Create</code>和<code>Edit</code>方法更新<code>[Bind]</code>特性以包含<code>Height</code>屬性。

為了顯示新的字段還要更新視圖模闆。

打開Index.cshtml、Create.cshtml、Edit.cshtml等檔案,添加新的<code>Height</code>字段。

然後需要更新資料庫以包含新的字段。如果沒有更新,此時運作将報錯,因為更新後User模型類和已存在的資料庫User表的結構不一緻。

有以下幾種方案來解決該錯誤:

EF可以基于新的模型類自動删除并重建資料庫。開發階段在測試資料庫上做開發還是比較友善的,但是你會丢失資料庫中的現有資料。是以該方案不适用于生産環境資料庫!

顯式修改現有資料庫的結構,使得它與模型類相比對,這個方案可以讓你保留資料庫的現有資料。你可以通過手動或者資料庫腳本來進行變更。

使用Code First Migrations來更新資料庫結構。

這裡采用第三種方案,運作如下指令:

<code>migrations add</code>指令告訴Migration架構去檢查目前的<code>User</code>模型類和目前的<code>User</code>資料庫表結構是否一緻。如果不一緻,就建立必要的代碼來遷移資料庫到新的模型類。

在Models目錄下添加<code>UserDeptViewModel</code>類:

這個視圖模型(View Model)将包含:

使用者清單<code>users</code>。

包含部門清單(depts)的<code>SelectList</code>,将用于視圖頁面中允許使用者去從清單中選擇一個部門。

<code>userDept</code>,包含使用者所選中的部門(dept)。

修改<code>Index</code>方法:

下面的代碼通過LINQ查詢從資料庫擷取所有的部門資料。

depts的<code>SelectList</code>是通過投影不重複的部門(<code>Distinct</code>)建立的。

首先删除最頂部的@model:

@model IEnumerable&lt;MyFirstApp.Models.User&gt;

替換成:

在<code>&lt;form&gt;</code>标記中添加:

在<code>&lt;table&gt;</code>标記中分别删除:

@Html.DisplayNameFor(model =&gt; model.Dept)

@foreach (var item in Model) {

最終的Index.cshtml檔案如下:

最終運作的頁面:

我的個人部落格

繼續閱讀