今日もちょいつか

お酒の飲み過ぎか、それとも歳のせいなのか毎日ちょっぴり疲れ気味なフリーのソフト屋です。ソフト開発の話題をblogにしてみます。

ASP.NET Core MVC MySQLのテーブルの内容をDropDownListにしてみた

Webシステムの開発をしていると、テーブルの内容をDropDownListにすることは
よくあることです。マスターデータなんか特にそうですよね。
で、ASP.NET Core MVCのことを色々と考えたり調べたりするのに飽きたので
サクッとコードを書いて、動いたーって喜んでみようと
DropDownListを試してみました。
そーしたら予想外にまたまたハマってしまいました。
まったく、初めてのことはことごとくハマってしまっています。

色々と苦労した結果動いたソース群を記しておきます。
いつものごとく、Visual Studio Community 2017 for Mac で動作確認しています。
自分なりにがんばってみた結果ですので、ASP.NET Core MVCの作法に合っているか不明です。
あくまでも参考程度にしてください。

やりたいことは、
Entity Frameworkを使ってMySQLのテーブルのデータを取得して
DropDownListを表示したい。

DropDownListに表示させたいModel

    public class ItemGrp
    {
        public int Id { get; set; }
        public string ItemGrpName { get; set; }
    }

DropDownList用のViewModelを作成

DropDownListに表示させるためにはViewModelが必要だったのです。
POSTで受け取った時の値も入ります。

    public class ItemGrpViewModel
    {
        [Required]
        public int ItemGrpList { get; set; }
    }

Controllerを準備します

DbContextからItemGrpのidと名称をを取得して、ViewBagへセットします。

        public IActionResult Index()
        {
            ViewBag.SelectOptions = _context.ItemGrp.ToArray().Select(m =>
            new SelectListItem() { Value = m.Id.ToString(), Text = m.ItemGrpName });                                                                      

            return View();
        }

Viewsを準備します

最後にViewへ @Html.DropDownListFor を使って表示します。

    @Html.DisplayNameFor(model => model.ItemGrpList)
    @Html.DropDownListFor(
      model => model.ItemGrpList,
      (IEnumerable<SelectListItem>)ViewBag.SelectOptions,
      " 選択してください ", 
      new { @class = "form-control" } )

最終的にDropDownListに対応するViewModelを準備することで
動いてくれましいた。
ViewをFormタグでくくって、POSTでサーバーへ渡した時に

        [HttpPost]
        public IActionResult Index(ItemGrpViewModel model)

このように、
コンストラクタにViewModelを定義することで値が取得できることもわかりました。
やっぱりViewにはバインドさせるModelが必要なのですね。

仕事の気分転換に、自立式ハンモック

以前からハンモックに憧れていたのですが。
屋内で使える自立式ハンモックがあるのですね。
どんなのが良いのかわからないので、1万円を切るくらいのを買ってみました。
想像していたより気持ちがいいです。
特に左右に揺らすととても気分が癒やされます。
プログラムでハマった時に気持ちを落ち着けることができそうです。

ASP.NET Core MVC MacでMySQLのMigrationが結構ハマりました

Visual Studio Community 2017 for Macを使ってASP.NETの開発をしているのですが
データベース(MySQL)のMigrationを動かすことができずにかなり悩んでしまいました。
最初はなんでもはまってしまうものです。

調べてみると、
Migrationの操作方法は
Package Manager Consoleで操作する方法と
dotnet ef コマンドによる操作があるようです。

このどちらもうまくゆきません。
まず、Package Manager Console ですが
Visual Studio Community 2017 for Macのどこを探しても
発見できないのです。

また、dotnet ef コマンドをTerminalから打ち込んでみるも
「コマンド "dotnet-ef" に一致する実行可能ファイルが見つかりません」
となってしまいます。

とりあえず、Package Manager Consoleの方から
じっくり調べてみました。
すると、なんと!for MacにはPackage Manager Consoleが存在しないようです。
マイクロソフトの公式サイト(英語)にありました。
docs.microsoft.com
日本語に訳して画像にしてみました。
f:id:Heinlein:20180118114234p:plain
MacでのPackage Manager Consoleの利用は無理のようです。

では、dotnet ef コマンドをTerminalから操作するしかありません。
いろいろと調べてみると
dotnet ef コマンドは、

Microsoft.EntityFrameworkCore.Tools.DotNet

で提供されているようです。
どうやらMicrosoft.EntityFrameworkCore.Tools.DotNetをインストールしないといけないようです。
NuGetではインストールできなくて(実際エラーになります)
直接プロジェクトファイルを編集しないといけないようです。
.csprojをエディタで開いて以下を追記します。

  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" />
  </ItemGroup>

追加したら、Terminalから

dotnet restore 

の実行で、dotnet ef コマンドが使えるようになりました。

マイグレーションファイルの作成は

dotnet ef migrations add マイグレーション名

マイグレーション実行は

dotnet ef database update

となります。

マイグレーションを実行するとちゃんとMySQLへテーブルが作成されました。
そしてMySQLの中に「__EFMigrationsHistory」テーブルも作成されます。
このテーブルにマイグレーションを実行した履歴が残りますので
次回にマイグレーションを実行する際はこの履歴テーブルに無い
マイグレーションファイルが実行されるわけです。

この仕組を使うと、
ローカルの開発環境からサーバーのデータベース環境への適用ががとても簡単になりますので
積極的に使ってゆきたいと思います。

ASP.NET Core MVC LINQを使ってみる

LINQ (Language Integrated Query) についてまとめてみました。
ASP.NET MVCで開発するには必須の技術となっています。
いままでだと、データベースシステムを開発するときには
SQLを駆使して処理を作成していましたが
ASP.NET MVCではDbContextに格納されたデータに対して
LINQを使って必要なデータを取得するのが作法となっているようです。
新しいことを覚えるのは大変ですが、学ぶのは楽しいことでもあります。
動作は、Visual Studio Community 2017 for Mac で行なっています。

動作確認に利用するデータ

LINQの動作確認に利用するデータ定義です。

var members = new[]{
      new { id = 1, Name = "ゆきこ", Age = 30, SexID = 2},
      new { id = 2, Name = "ようこ", Age = 5 , SexID = 2},
      new { id = 3, Name = "ひろし", Age = 10, SexID = 1}
};
var sex = new[]{
      new { id = 1, Text = "男" },
      new { id = 2, Text = "女"}
};

クエリキーワード[group・by]

指定したキー値にもとづいて、グループ化した結果を返すことができます。

var q =
      from p in members
      orderby p.SexID
      group p by p.SexID;
            
      foreach(var g in q)
      {
          Console.WriteLine("----/" + g.Key.ToString() + "/----");
          foreach (var x in g) Console.WriteLine(x);
      }

実行結果はこうなります。

----/ 1 / ----
{ id = 3, Name = ひろし, Age = 10, SexID = 1 }
----/ 2 / ----
{ id = 1, Name = ゆきこ, Age = 30, SexID = 2 }
{ id = 2, Name = ようこ, Age = 5, SexID = 2 }

同じ処理をメソッド構文で記述してみます。

var m = members
       .OrderBy(x => x.SexID)
       .GroupBy(x => x.SexID);

クエリキーワード[orderby・ascending・descending]

各要素の値にもとづいてクエリ式で返す結果を並べ替えます。

var q =
      from p in members
      orderby p.SexID descending, p.Name
      select p;
      foreach(var x in q)
      {
         Console.WriteLine(x);
      }

この例だと、性別で降順にしてなおかつ名前で昇順にしています。
実行結果は

{ id = 1, Name = ゆきこ, Age = 30, SexID = 2 }
{ id = 2, Name = ようこ, Age = 5, SexID = 2 }
{ id = 3, Name = ひろし, Age = 10, SexID = 1 }

同じ内容をメソッド構文で記述してみました。

var m = members
      .OrderByDescending(x => x.SexID)
      .ThenBy(x => x.Name);

二つ目のソート条件を記述するのがクエリ構文と違って戸惑いました。

クエリキーワード[ join・in・on・equals ]

指定した値が一致している複数のデータソースを結合します。
よくある、コードから名前表示みたいな感じです。

var q =
      from m in members
      join s in sex on m.SexID equals s.id
      select new { m.id, m.Name, Sex = s.Text };
      foreach(var x in q)
      {
          Console.WriteLine(x);
      }

性別コードから性別を表示しています。
実行結果は

{ id = 1, Name = ゆきこ, Sex = 女 }
{ id = 2, Name = ようこ, Sex = 女 }
{ id = 3, Name = ひろし, Sex = 男 }

これを、メソッド構文で記述すると

var query = members.Join(
        sex,
        (x) => x.SexID,
        (y) => y.id, (x, y) => new {
                                     id = x.id, 
                                     Name = x.Name, 
                                     Sex = y.Text
});

恐ろしきラムダ式ですね。
書いている内容が呪文のようで理解ができません。
これは慣れるしかないのですかねー。

最後に

LINQにはクエリ構文とメソッド構文がありますが
メソッド構文で記述するとパット見、何をしているかわからない感じもあるので
クエリ構文がいいかなーと思ってしまいます。
できればどちらかに統一したい思いもありますので
どちらの構文を利用するか悩むところです。

仕事の気分転換に、自立式ハンモック

以前からハンモックに憧れていたのですが。
屋内で使える自立式ハンモックがあるのですね。
どんなのが良いのかわからないので、1万円を切るくらいのを買ってみました。
想像していたより気持ちがいいです。
特に左右に揺らすととても気分が癒やされます。
プログラムでハマった時に気持ちを落ち着けることができそうです。

ASP.NET Core MVC Dapperを使ったMySQLアクセス

前回は、Entiry Framework を使ったMySQLの操作をまとめてみました。
heinlein.hatenablog.com
SQLを直接書かないし、少ないコードでここまでやってくれるのかって感じでしたが
実際にシステムを開発しようとすると、
Entiry Framework の形に合わせなくてはならず
複雑な処理をプログラミングするのにちょっと難しいと感じていました。

そこで、発見したのが「Dapper」です。
直接SQL文を利用することができて自由度が高そうです。
ADO.NET より扱いやすくて、Entiry Frameworkより自由な感じです。
では、MySQLからテーブルの内容を読み込んでみます。
動作は、Visual Studio Community 2017 for Mac で行なっています。

NuGetでパッケージ追加

Dapperを利用するのに必要な「Dapper」パッケージを追加します。
MySQLを扱うので「MySql.Data」も同様に追加します。

データベース環境とModel「ItemGrp.cs」は前回のEntiry Frameworkで使ったものを
そのまま使います。

サンプルコード

適当なControllerにコードを記述します。

using Dapper;
using MySql.Data.MySqlClient;
public IActionResult Index()
{
    string ItemGrpNames = "";
    using (var connection = new MySqlConnection("server=localhost;database=testdb;uid=root;pwd=パスワード"))
    {
        connection.Open();

        var itemGrps = connection.Query<ItemGrp>("SELECT * FROM ItemGrp");

        foreach (var itemGrp in itemGrps)
        {
            ItemGrpNames += " - " + itemGrp.ItemGrpName;
        }
    }
    ViewData["ItemData"] = ItemGrpNames;
    return View();
}

コード自体はすごくわかりやすく記述することができます。
今までプログラミングしていた形に近いのですんなりと書けそうです。
基本的にはEntiry Frameworkを使いますが
Entiry Frameworkでの記述が難しい時にはDapperを使うと
なんとかシステム開発を進めて行けそうです。

ASP.NET Core MVC Entiry Frameworkを使ったMySQLアクセス

ASP.NET CoreでのMySQLへのアクセスについて
Entiry Frameworkを利用した方法を試してみます。
いわゆるO/Rマッパーで具体的にはDbContextクラスを使って
MySQLからテーブルの内容を読み込んでみます。
動作は、Visual Studio Community 2017 for Mac で行なっています。

データベースの準備

動作確認に必要なテーブルを作成します。
Primary keyの他に名称があるだけの単純なテーブルです。

CREATE TABLE ItemGrp 
(
     id  int NOT NULL AUTO_INCREMENT,
     ItemGrpName  text,
 PRIMARY KEY (id)
)
ENGINE = InnoDB;

Models作成

テーブルに対応するModel「ItemGrp.cs」を作成します。

public partial class ItemGrp
 {
     public int Id { get; set; }
     public string ItemGrpName { get; set; }
 }

DbContext作成

データベースへのアクセスに使用するDbContextクラスを作成します。
今回は、プロジェクトの直下に「DataContext.cs」を作成しました。

public class DataContext : DbContext
{
    public DbSet<ItemGrp> ItemGrp { get; set; }
}

appsettings.jsonの修正

appsettings.jsonMySQL接続文字列を追記します。

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": {
    "MySQL": "Database=testdb;Data Source=localhost;User Id=root;Password=パスワード"
  }
}

NuGetでパッケージ追加

Entiry Frameworkを利用するのに必要な
Microsoft.EntityFrameworkCore」と「Pomelo.EntityFrameworkCore.MySql
パッケージを追加します。

Startup.csの修正

Startupクラスに必要な記述を追加します。
まず、appsettings.jsonへ記述したMySQL接続文字列を取得できるように
クラスのコンストラクタを書き換えます。

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables();
    Configuration = builder.Build();
}

そして、ConfigureServicesメソッドに
DbContextがMySQL接続文字列を使って接続でききるように追加します。

using Microsoft.EntityFrameworkCore;
services.AddDbContext<DataContext>(options =>
    options.UseMySql(Configuration.GetConnectionString("MySQL")));

Controllers作成

ItemGrpController.csを作成してデータベースアクセスに必要なコードを
追加します。

using Microsoft.EntityFrameworkCore;
public class ItemGrpController : Controller
{
    private readonly DataContext _context;
    public ItemGrpController(DataContext context)
    {
        _context = context;
    }

    // GET: /<controller>/
    public async Task<IActionResult> Index()
    {
        return View(await _context.ItemGrp.ToListAsync());
    }
}

MySQLのテーブルからデータを取得するのにこんな簡単なコードで
実現できます。
ItemGrpControllerのコンストラクタでDbContextオブジェクトがそのまま渡されます。
最終的には_context.ItemGrpを使ってテーブルのItemGrpへアクセスします。
そしてテーブル内のデータをリスト化するために
ToListAsyncメソッドを呼び出します。
リスト化されたデータはViewメソッドを使ってIndexページに渡されます。

Viewを作成

一覧を表示する Index.cshtml を作成します。

@model IEnumerable<MasterTest.Models.ItemGrp>

<h2>index</h2>

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Id)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ItemGrpName)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(model => item.Id)
            </td>
            <td>
                @Html.DisplayFor(model => item.ItemGrpName)
            </td>
        </tr>
}
    </tbody>
</table>

思ったよりも簡単に実現することができました。
簡単なマスタ画面だったら工数をかけずにサクッとできそうです。
ただ、実際にシステムはこんなに単純ではなく
一度の処理でいろんなテーブルを読み書きしなければなりませんので
そんな場合はどのようにするのか?今後の課題となります。

かっこいいApple小物のご紹介

Apple Watch 充電 スタンドです。
Apple Watchをセットすると、ちょうどディプレイのようになるカッコよさ。
形状が90年代のMacintoshなのがとても嬉しいです!

ASP.NET Core MVCにAdminLTE-2.4.2を組み込んでみる

ASP.NET Core MVCで開発をしてゆきたいのですが
管理画面のデザインがすっごく苦手なので
楽チンでかっこいいデザインが簡単にできるBootstrap3をベースにしたAdminLTEを
利用してみようと思います。
実際にASP.NET Core MVCで利用できるまでを調べてみました。
環境は、Visual Studio Community 2017 for Mac で行なっています。

AdminLTEダウンロード

Free Bootstrap Admin Template | AdminLTE.IO
こちらから最新版をダウンロードします。
2017年12月現在では、2.4.2となっています。

ファイルをプロジェクトへコピー

MVCプロジェクトのwwwrootフォルダ直下へ
ダウンロードしたファイル群をコピーします。
ちなみにフォルダ名は「AdminLTE-2.4.2」としました。

_Layout.cshtmlを修正

今回はAdminLTEのデモ画面であるstarter.htmlを表示してみたいので
starter.htmlからコピーして組みこんてゆきます。
・<head>内へstarter.htmlの<head>をコピー。
・<script>内へstarter.htmの<script>をコピー。
どちらも全て削除してからコピーします。
そして、コピーしたソースのパスを全て修正します。
こんな感じ

href="bower_components/bootstrap/dist/css/bootstrap.min.css">

パスの頭に「~/AdminLTE-2.4.2/」を追加します。

href="~/AdminLTE-2.4.2/bower_components/bootstrap/dist/css/bootstrap.min.css">

_Layout.cshtmlのbodyを修正

・<body>タグを <body class="hold-transition skin-blue sidebar-mini"> へ変更します。
・メイン部分を<div class="wrapper">で囲みます。
・メイン部分を囲む
   <div class="container body-content"> を
   <div class="content-wrapper"> へ変更します。

最後にメニューなどのコンテンツをコピー

starter.htmlから各コンテンツをコピーします。
・メイン部分の上に <header class="main-header"></header> をコピー。
・メイン部分の上 <header>の下に <aside class="main-sidebar"></aside> をコピー。
・メイン部分の下に<footer class="main-footer"></footer> をコピー。

最終的にこんな感じになりました。
メイン部分にASP.NETが出力したHtmlが表示されています。
f:id:Heinlein:20171213153719p:plain
最終的な_Layout.cshtmlのHtmlはこんな感じです。
Visual Studio だとブロック毎に折りたたまれているのでとても見やすいです。
f:id:Heinlein:20171213192821p:plain
html的には、利用しないソースもまだたくさん含まれていますので
使わない所はどんどん削除していって
スッキリしたhtmlにして開発を進めたいと思います。

ASP.NET Core MVC Zipファイル作成

ASP.NET Core MVCでZipファイルを作成する方法を調べてみました。
Visual Studio Community 2017 for Macで動作確認をしています。

NuGetでパッケージの追加

NuGetを使って「System.IO.Compression」パッケージをを追加します。

Zipファイル作成のサンプルコード

using System.IO.Compression;

string zipFileName = "ExcelFile/DownTmp/hatena.zip";
using (var zFile = ZipFile.Open(@zipFileName, ZipArchiveMode.Update))
{
     zFile.CreateEntryFromFile(@"ExcelFile/OrgFile.xlsx", "OrgFile.xlsx", CompressionLevel.Optimal);
}

ExcelFile/DownTmpフォルダにhatena.zipファイルを作成して
ExcelFileフォルダにあるOrgFile.xlsxを追加しています。