Entity Framework CoreでMySQLのinformation_schema.TABLESを取得する

## やりたいこと
タイトルママ。
Entity Framework CoreでMySQLのinformation_schema.TABLESを取得する。
ただし、生SQLは使わない。

## 環境
MySQL(MariaDB) 5.5.60
Visual Studio 2017
.NET Core 2.1
Microsoft.EntityFrameworkCore 2.2.2
Microsoft.EntityFrameworkCore.Tools 2.2.2
Microsoft.NETCore.App 2.1
Pomelo.EntityFrameworkCore.MySql 2.2.0
（Oracle純正のMySql.Data 8.0.15だとinformation_schema.TABLESテーブルで使われているbigint unsignedの型変換に失敗するため、安定のPomeloを使用する）

## ソースコード
新規プロジェクトの「コンソールアプリ(.Net Core)」をベースとしています。
なお、ソースコードにテーブル「Blogs」「Posts」も定義しておりますが確認用のダミーテーブルです。

optionsBuilder.UseMySql()メソッド内の接続文字列は適宜変更のこと。

```csharp:BloggingContext.cs
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace EntityFrameworkConsoleApp
{
    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
        public DbSet<InformationSchemaTable> InformationSchemaTables { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySql("Server=localhost;Port=3306;User ID=dotnetcore;Password=dotnetcore;Database=dotnetcore;Connection Timeout=30;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // information_schema.TABLESに主キーは存在しないがEntityFramework的に主キーが存在しないテーブルはエラーになるので設定する
            modelBuilder.Entity<InformationSchemaTable>()
                .HasKey(c => new { c.TableCatalog, c.TableSchema, c.TableName, c.TableType });
        }
    }

    /// <summary>
    /// ただのダミーテーブル
    /// </summary>
    public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }

        public ICollection<Post> Posts { get; set; }
    }

    /// <summary>
    /// ただのダミーテーブル
    /// </summary>
    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public int BlogId { get; set; }
        public Blog Blog { get; set; }
    }

    /// <summary>
    /// information_schema.TABLESテーブル
    /// </summary>
    [Table("TABLES", Schema = "information_schema")]
    public class InformationSchemaTable
    {
        [Column("TABLE_CATALOG")]
        public string TableCatalog { get; private set; }
        
        [Column("TABLE_SCHEMA")]
        public string TableSchema { get; private set; }
        
        [Column("TABLE_NAME")]
        public string TableName { get; private set; }
        
        [Column("TABLE_TYPE")]
        public string TableType { get; private set; }

        [Column("ENGINE")]
        public string Engine { get; private set; }

        [Column("VERSION")]
        public ulong? Version { get; private set; }

        [Column("ROW_FORMAT")]
        public string RowFormat { get; private set; }

        [Column("TABLE_ROWS")]
        public ulong? TableRows { get; private set; }

        [Column("AVG_ROW_LENGTH")]
        public ulong? AvgRowLength { get; private set; }

        [Column("DATA_LENGTH")]
        public ulong? DataLength { get; private set; }

        [Column("MAX_DATA_LENGTH")]
        public ulong? MaxDataLength { get; private set; }

        [Column("INDEX_LENGTH")]
        public ulong? IndexLength { get; private set; }

        [Column("DATA_FREE")]
        public ulong? DataFree { get; private set; }

        [Column("AUTO_INCREMENT")]
        public ulong? AutoIncrement { get; private set; }

        [Column("CREATE_TIME")]
        public DateTime? CreateTime { get; private set; }

        [Column("UPDATE_TIME")]
        public DateTime? UpdateTime { get; private set; }

        [Column("CHECK_TIME")]
        public DateTime? CheckTime { get; private set; }

        [Column("TABLE_COLLATION")]
        public string TableCollation { get; private set; }

        [Column("CHECKSUM")]
        public ulong? Checksum { get; private set; }

        [Column("CREATE_OPTIONS")]
        public string CreateOptions { get; private set; }

        [Column("TABLE_COMMENT")]
        public string TableComment { get; private set; }
    }
}
```

```csharp:Program.cs
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;

namespace EntityFrameworkConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var db = new BloggingContext())
            {
                // ダミーレコード追加
                for (int i = 0; i < 1000; i++)
                {
                    db.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" + i.ToString() });
                }
                db.SaveChanges();

                // 念願のinformation_schema.TABLESテーブル取得＆表示
                Console.WriteLine("使用テーブル名やレコード数取得とか");
                foreach (var table in db.InformationSchemaTables.AsNoTracking().Where(p => p.TableSchema == db.Database.GetDbConnection().Database))
                {
                    Console.WriteLine(" - {0} {1}", table.TableName, table.TableRows);
                }
            }

            Console.ReadKey();
        }
    }
}
```

## マイグレーション生成
```console:パッケージマネージャーコンソール
PM> Add-Migration Migration1
To undo this action, use Remove-Migration.
```

## マイグレーションで生成されたソースコードを修正
information_schemaに対するマイグレーションコードをコメントアウトor削除します。全3箇所。
（除外できるAttributeがあると嬉しいのですが…）

```csharp:Migrations/xxxxxxxxxxxxxx_Migration1.cs
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;

namespace EntityFrameworkConsoleApp.Migrations
{
    public partial class Migration1 : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            //migrationBuilder.EnsureSchema(
            //    name: "information_schema");

            migrationBuilder.CreateTable(
                name: "Blogs",
                columns: table => new
                {
                    BlogId = table.Column<int>(nullable: false)
                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
                    Url = table.Column<string>(nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Blogs", x => x.BlogId);
                });

            //migrationBuilder.CreateTable(
            //    name: "TABLES",
            //    schema: "information_schema",
            //    columns: table => new
            //    {
            //        TABLE_CATALOG = table.Column<string>(nullable: false),
            //        TABLE_SCHEMA = table.Column<string>(nullable: false),
            //        TABLE_NAME = table.Column<string>(nullable: false),
            //        TABLE_TYPE = table.Column<string>(nullable: false),
            //        ENGINE = table.Column<string>(nullable: true),
            //        VERSION = table.Column<ulong>(nullable: true),
            //        ROW_FORMAT = table.Column<string>(nullable: true),
            //        TABLE_ROWS = table.Column<ulong>(nullable: true),
            //        AVG_ROW_LENGTH = table.Column<ulong>(nullable: true),
            //        DATA_LENGTH = table.Column<ulong>(nullable: true),
            //        MAX_DATA_LENGTH = table.Column<ulong>(nullable: true),
            //        INDEX_LENGTH = table.Column<ulong>(nullable: true),
            //        DATA_FREE = table.Column<ulong>(nullable: true),
            //        AUTO_INCREMENT = table.Column<ulong>(nullable: true),
            //        CREATE_TIME = table.Column<DateTime>(nullable: true),
            //        UPDATE_TIME = table.Column<DateTime>(nullable: true),
            //        CHECK_TIME = table.Column<DateTime>(nullable: true),
            //        TABLE_COLLATION = table.Column<string>(nullable: true),
            //        CHECKSUM = table.Column<ulong>(nullable: true),
            //        CREATE_OPTIONS = table.Column<string>(nullable: true),
            //        TABLE_COMMENT = table.Column<string>(nullable: true)
            //    },
            //    constraints: table =>
            //    {
            //        table.PrimaryKey("PK_TABLES", x => new { x.TABLE_CATALOG, x.TABLE_SCHEMA, x.TABLE_NAME, x.TABLE_TYPE });
            //    });

            migrationBuilder.CreateTable(
                name: "Posts",
                columns: table => new
                {
                    PostId = table.Column<int>(nullable: false)
                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
                    Title = table.Column<string>(nullable: true),
                    Content = table.Column<string>(nullable: true),
                    BlogId = table.Column<int>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Posts", x => x.PostId);
                    table.ForeignKey(
                        name: "FK_Posts_Blogs_BlogId",
                        column: x => x.BlogId,
                        principalTable: "Blogs",
                        principalColumn: "BlogId",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateIndex(
                name: "IX_Posts_BlogId",
                table: "Posts",
                column: "BlogId");
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Posts");

            //migrationBuilder.DropTable(
            //    name: "TABLES",
            //    schema: "information_schema");

            migrationBuilder.DropTable(
                name: "Blogs");
        }
    }
}
```

## マイグレーション実行
マイグレーションを実行します。

```console:パッケージマネージャーコンソール
PM> Update-Database
Applying migration 'xxxxxxxxxxxxxx_Migration1'.
Done.
```

## プログラム実行
プログラムを実行します。

```console:実行結果
使用テーブル名やレコード数取得とか
 - __efmigrationshistory 1
 - blogs 1000
 - posts 0
```

SQL文的には

```sql
select TABLE_NAME, TABLE_ROWS from information_schema.tables where table_schema=database();
```

と言った感じでしょうか。