[ASP.NET MVC][筆記] 利用 TryUpdateModel 來做資料更新 (二) - ViewModel 篇


第一篇說明了 TryUpdateModel 的簡單的應用,除了可指定更新的欄位之外也可排除更新特定的欄位,而因為可搭配 Metadata 做欄位驗證為資料又做了一層把關,但在 ASP.NET MVC 中我們也很常針對每個的頁面(View)定義專屬的 ViewModel ,而若照個第一篇的寫法會發現欄位無法正確繫結,所以這篇就來教大家如何正確利用 TryUpdateModel 來為我們的 ViewModel 做資料更新 ~

前言

第一篇說明了 TryUpdateModel 的簡單的應用,除了可指定更新的欄位之外也可排除更新特定的欄位,而因為可搭配 Metadata 做欄位驗證為資料又做了一層把關,但在 ASP.NET MVC 中我們也很常針對每個的頁面(View)定義專屬的 ViewModel ,而若照個第一篇的寫法會發現欄位無法正確繫結,所以這篇就來教大家如何正確利用 TryUpdateModel 來為我們的 ViewModel 做資料更新 ~

說明

首先我們先定義一個 ViewModel 如下:

    public class ProductViewModel
    {
        public Product ViewProduct { get; set; }
    }

透過 ViewModel 所產生的 View 如下:

@model MvcTemplete.Models.ProductViewModel
@{
    ViewBag.Title = "Edit";
}

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Product</legend>

        @Html.HiddenFor(model => model.ViewProduct.ProductId)
        <div class="editor-label">
            @Html.LabelFor(model => model.ViewProduct.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ViewProduct.Name)
            @Html.ValidationMessageFor(model => model.ViewProduct.Name)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.ViewProduct.Ename)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ViewProduct.Ename)
            @Html.ValidationMessageFor(model => model.ViewProduct.Ename)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.ViewProduct.ModifyUid)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ViewProduct.ModifyUid)
            @Html.ValidationMessageFor(model => model.ViewProduct.ModifyUid)
        </div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}
</span>

接下來我們先看看 Post 回 Controller 時 FormCollection 所接收到集合,如下:

由上圖可看到在每個 Key 中包含了 ViewProduct 這個前置詞,因為在 ViewModel 裡我們使用了 Prodcut 這個 Model 且命名為 ViewProduct,如果讀者照著上一篇的 TryUpdateModel 的方法,程式會無法成功繫結。

此時我們可以利用 TryUpdateModel 的另外一個多載來達到資料繫結,程式碼如下:

if(TryUpdateModel(product, "ViewProduct"))
{
     db.SaveChanges();
}

而若希望更新特定欄位或排除特定欄位,如下:

if(TryUpdateModel(product, "ViewProduct",new string[] {"Name"},new string[] {"ModifyUid"}))
{
     db.SaveChanges();
}

上面的執行結果僅會更新 Name 欄位,而排除更新 ModifyUid 這個欄位。


當然上面的方法還是不夠完美,因為我們並沒有搭配 FormCollection 來做資料繫結並排除特定欄位 ,但因為 FormCollection 內的 Keys 是有加上前置詞,導致無法成功繫結並更新,這部份筆者有寫了個轉換的Code來去掉前置詞,如下:

            var Keys = formValue.AllKeys;
            List newKeys = new List();
            foreach (var item in Keys)
            {
                newKeys.Add(item.Replace("ViewProduct.", ""));
            }
            if (TryUpdateModel(product, "ViewProduct", newKeys.ToArray(), new string[] { "ModifyUid" }))
            {
                db.SaveChanges();
            }

OK !大功告成 ~ 不過不知道有沒有其他大大能針對 FormCollection 有前置詞的部份能有其他更好的解法,因為這個解法只是單純去做字串取代而已(逃)。

總結

只能說 TryUpdateModel 在實務上的應用太強大了,如果能善加利用其提供的多載鐵定能應用各種不同的需求,當然還是提醒一下大家使用 TryUpdateModel 時還是要加入「黑名單」或「白名單」,來讓我們的資料更加正確!


新手發文,如有錯誤煩請告知,感謝。
如果喜歡我的文章請按推薦,有任何問題歡迎下面留言~~~

 

 

簽名:

學習這條路很廣,喜歡什麼技術不重要,重要的是你肯花時間去學習