ASP.NET MVC5でTodoリストを作成

## はじめに
こんにちは。初めて投稿致します。
ラクス[Advent Calendar 2019](https://qiita.com/advent-calendar/2019/rakus)の12日目の記事です。昨日は[@soachrさんのPostgreSQLに関する記事](http://soachr.hatenablog.com/entry/2019/12/11/000000)でした。
私は今年の半ばごろまでjavascriptに触れてきましたが、今度は業務でC#を使用することとなり現在絶賛勉強中です。
今回は業務で使用しているC#のフレームワークであるASP.NET MVC5を用いてTodoリストを作成いたしました。
## 使用したツール
- Visual Studio Community 2019
- SQL Server 2017 Developer
- SQL Server Management Studio 18(SSMS)

## DB及びTableの作成
まずSQLServerにDBとテーブルを作成します。
使用したCreate文は以下の通りです。

```sql
CREATE TABLE dbo.MVCList(
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
DoneFlg bit NOT NULL,
TodoName nvarchar(50) NOT NULL,
DeadLine date NULL,
Remarks nvarchar(50) NULL
); 
```
## プロジェクトの作成
1. VisualStudioを開き「新しいプロジェクトの作成」をクリックします。
2. 次にASP.NET Webアプリケーション(.NET Framework)を選択しプロジェクト名を入力します。
　　![project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/6f565b6d-ef78-467b-8185-865a7d96355d.png)
3. MVCを選択して作成を押します。
　![MVC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/a7ecec7d-d569-c6a2-d9af-770867b40189.png)

すると、下記のようなディレクトリ構成のプロジェクトができあがります。
![ディレクトリ構成.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/8605c9af-a6be-0670-d3ce-0d473ca8b491.png)

## EntityFrameworkとjQueryのインストール
下記手順でEntityFrameworkと(必要な場合は)jQueryをインストールして下さい。
1. ソリューションを右クリックし、ソリューションのNuGetパッケージの管理を選択。
2. EntityFrameworkとjQueryを検索しインストールを実施
3. ソリューションを右クリックしビルドを行う。

## Modelの作成
1. Modelフォルダを右クリック ⇒ 追加 ⇒ 新しい項目を選択します。
2. 「データ」の「ADO.NET Entity Data Model」を選択しファイル名を入力します。
　　<img width="708" alt="Model作成.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/b8a62bdf-1890-3fa8-0a96-61e1d85fae97.png">
3. モデルのコンテンツの選択画面で「データベースからCode First」を選択します。
4. Modelフォルダ配下にModelとDBContextが生成されます。

## ControllerとViewの作成
1. Controllersフォルダを右クリックし追加 ⇒ コントローラを選択します。
2. 次に「Entity Frameworkを使用した、ビューがあるMVC5コントローラ」を選択します。
　<img width="707" alt="コントローラ作成.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/068ba611-9d31-db68-3f02-be4d33c1b490.png">
3. モデルクラスとデータコンテキストクラスをリストから選択し、ファイル名を入力します。
　　<img width="451" alt="コントローラ作成2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/b6fd3361-ecd0-a0e0-1e46-287328330262.png">

※名前が紛らわしいですが、MVCTodoがデータコンテキストになります。
4. コントローラと一緒にViewであるcshtmlファイルも生成されます。
　<img width="285" alt="View.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/5afb92e3-ec68-69ed-52ec-bfc29ed0a325.png">

※今回はTodoリストの作成なのでDetail.cshtmlは削除します。

## 生成されたファイルの手直し
### Modelファイル
・IDと完了フラグ以外の項目に **[DisplayName("題名")]**を追加しTodoリストの題名を日本語で表示するようにしました。
・期日に**[DataType(DataType.Date)]**を追加しdate型で表示・入力できるようにしました。

``` MVCList.cs
namespace MVCTodoList.Models
{
    using System;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
   

    [Table("MVCList")]
    public partial class MVCList
    {
        // ID
        public int ID { get; set; }

        // 完了チェック
        public bool DoneFlg { get; set; }

        // やること
        [DisplayName("やること")]
        [Required]
        [StringLength(50)]
        public string TodoName { get; set; }

        // 期日
        [DisplayName("期日")]
        [DataType(DataType.Date)]
        [Column(TypeName = "date")]
        public DateTime? DeadLine { get; set; }

        // 備考
        [DisplayName("備考")]
        [StringLength(50)]
        public string Remarks { get; set; }
    }
}
```
### 一覧（Index）ファイル
＠section scripts{}でjavascriptファイルを読み込むようにしました。
チェック欄はDisplayForのままだとチェックボックスが非活性なので、CheckboxForへ変更し活性にしました。
更にcheckboxForの引数に**new{id=item.ID}**を入れてidにテーブルのIDが振られるように変更しました。

``` Index.cshtml
@model IEnumerable<MVCTodoList.Models.MVCList>

@{
    ViewBag.Title = "Index";
}

@section scripts{
    <script type="text/javascript" src="../Scripts/own/MvcList.js"></script>
}

<h2>やることリスト</h2>

<p>
    @Html.ActionLink("やること追加", "Create")
</p>
<table>
    <tr>
        <th></th>
        <th>
            @Html.DisplayNameFor(model => model.TodoName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.DeadLine)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Remarks)
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {

        <tr name="row">
            @*チェック欄*@
            <td>
                @Html.CheckBoxFor(modelItem => item.DoneFlg,new { id=item.ID})
            </td>
            @*やったこと*@
            <td name="name">
              @Html.DisplayFor(modelItem => item.TodoName)
            </td>
            @*期日*@
            <td name="deadline">
                @Html.DisplayFor(modelItem => item.DeadLine)
            </td>
            @*備考*@
            <td name="remarks">
                @Html.DisplayFor(modelItem => item.Remarks)
            </td>
            <td>
                @Html.ActionLink("修正", "Edit", new { id = item.ID }) |
                @Html.ActionLink("削除", "Delete", new { id = item.ID })
            </td>
        </tr>

    }

</table>
```
### Ajax通信用JSファイル
チェック欄のAjax通信用に新たにjavascriptファイルを作成しました。jQueryで実装しています。

``` MVCList.js
$(function () {

    // チェックボックスの状態をchangeイベントで監視
    $('[name="item.DoneFlg"]').change(function (ele) {
        // チェック状態を取得
        var checkFlg = !!ele.target.checked;
        // チェンジイベントが走ったデータのIDを取得
        var intId = parseInt(ele.target.id); 
        
        var param = {
            Id: intId,
            DoneFlg : checkFlg
        }

        $.ajax({
            url: '/MVCLists/Check',
            type: "POST",
            dataType: "json",
            data: param
        })
    })
});
```
### Controllerファイル
一覧画面のチェックボックスの状態を登録するCheckメソッドを追加しました。
詳細（Detail)関連のメソッドは削除しました。

``` MVCListsController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using MVCTodoList.Models;

namespace MVCTodoList.Controllers
{
    public class MVCListsController : Controller
    {
        private MVCContext db = new MVCContext();

        // 一覧画面の表示
        public ActionResult Index()
        {
            return View(db.MVCList.ToList());
        }

        // 一覧画面のチェックボックスの状態を登録
        [HttpPost]
        public ActionResult Check(int Id, bool DoneFlg)
        {
            MVCList mvcList = db.MVCList.Find(Id);
            mvcList.DoneFlg = DoneFlg;
            db.Entry(mvcList).State = EntityState.Modified;
            db.SaveChanges();
            return Json(mvcList);
        }

        // 新規登録画面の表示
        public ActionResult Create()
        {
            return View();
        }

        // 新規登録
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "ID,DoneFlg,TodoName,DeadLine,Remarks")] MVCList mVCList)
        {
            if (ModelState.IsValid)
            {
                db.MVCList.Add(mVCList);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(mVCList);
        }

        // 編集画面の表示
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            MVCList mVCList = db.MVCList.Find(id);
            if (mVCList == null)
            {
                return HttpNotFound();
            }
            return View(mVCList);
        }

        // リストの内容の編集
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ID,DoneFlg,TodoName,DeadLine,Remarks")] MVCList mVCList)
        {
            if (ModelState.IsValid)
            {
                db.Entry(mVCList).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(mVCList);
        }

        // 削除画面の表示
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            MVCList mVCList = db.MVCList.Find(id);
            if (mVCList == null)
            {
                return HttpNotFound();
            }
            return View(mVCList);
        }

        // 削除処理
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            MVCList mVCList = db.MVCList.Find(id);
            db.MVCList.Remove(mVCList);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}
```
## 画面
データは事前に新規作成画面から入れました。
まだ二つのデータに完了チェックが入っていないので、テーブルのDoneFlgは0のままです。
<img width="1021" alt="画面.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/4e78ccc7-f647-f774-cd53-bf410d96fdde.png">
![テーブル値.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/a9354492-3ca5-80c8-df2c-eaf35210aca4.png)

「ノートを買う」にチェックを入れました。
すると、Ajax通信により「ノートを買う」のDoneFlgが「1」へ変更されました。
<img width="995" alt="画面チェック.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/f1aab7f3-f475-99bd-76c8-c7cba7fca395.png">
![画面チェック.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401696/c96ac89c-b807-636c-e48d-a9ab4349e269.png)

## まとめ
今回は仕事で触っているC#のフレームワークであるASP.NET MVC5とjQueryを使ってTodoリストを作成しました。
C#はまだまだ勉強中ですので、これからも精進致します。