20190811のC#に関する記事は2件です。

EntityFramework Core Code Firstでカラム順を整えたいときにやること。

Entity Framework Core Code-Firstは楽ちんだけれど……

Dotnetでデータベースを扱うとき、EntityFrameworkは楽チンでいいですね。
特にCode Firstは先にデータベースのテーブル設計を行わなくても、テーブルに対応するPOCOとDbContextを実装しておけば、それに合わせてテーブルを作成してくれるから楽ちん。NoSQLなくても十分やっていけるレベル。

しかし、EntityFrameworkにはちょいと問題がありまして。いや、開発においては全く問題ないのですが、後々のことを考えると、ね。

カラムが思ったとおりに並んでくれない!

思っていたクラスと実際のテーブル

例えば、ユーザ情報を保持するUserクラスがあったとします。Userクラスはエンティティ全てに共通するカラムを保持するEntityBaseクラスを継承します。

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace FilunK.Sample.DataAccess.DataModel
{
    public class EntityBase
    {
        [Column("CREATION_ID")]
        [Required]
        public string CreationId{get;set;}

        [Column("CREATION_PG")]
        [Required]
        public string CreationProgram{get;set;}

        [Column("CREATION_DATE")]
        public DateTime CreationDate{get;set;}

        [Column("UPDATE_ID")]
        [Required]
        public string UpdateId{get;set;}

        [Column("UPDATE_ID")]
        [Required]
        public string UpdateProgram{get;set;}

        [Column("UPDATE_DATE")]
        [Required]
        public DateTime UpdateDate{get;set;}

        [Column("DEL_FLAG")]
        [Required]
        public bool IsDeleted{get;set;}
    }


    [Table("T_USER", Schema = "SAMPLE")]
    public class User : EntityBase
    {
        [Key]
        [Range(8, 100)]
        [Column("USER_ID")]
        public string UserId { get; set; }

        [Required]
        [Column("SALT")]
        public string Salt { get; set; }

        [Required]
        [Column("HASH")]
        public string Hash { get; set; }

        [Required]
        [Column("ITERATION")]
        public int Iteration { get; set; }

        [Required]
        [Column("ACCOUNT_CONFIRMED")]
        public bool IsConfirmed { get; set; }
    }
}

このとき、期待しているテーブルの定義は以下のようなイメージでした。
※実際には文字列長を設定したりするので、厳密にこのSQLになるわけではありません。擬似的なSQLコードと見てもらえればと思います。

CREATE TABLE SAMPLE.USER {
     USER_ID TEXT PRIMARY KEY
    ,SALT TEXT
    ,HASH TEXT
    ,ITERATION INTEGER
    ,ACCOUNT_CONFIRMED BOOLEAN
    ,CREATION_ID TEXT
    ,CREATION_PG TEXT
    ,CREATION_DATE TIMESTAMP
    ,UPDATE_ID TEXT
    ,UPDATE_PG TEXT
    ,UPDATE_DATE TIMESTAMP
    ,DEL_FLAG BOOLEAN
}

ですが、実際には以下のようなSQLのイメージになってしまいます。

CREATE TABLE SAMPLE.USER {
     USER_ID TEXT PRIMARY KEY
    ,CREATION_DATE TIMESTAMP
    ,CREATION_ID TEXT
    ,CREATION_PG TEXT
    ,HASH TEXT
    ,ACCOUNT_CONFIRMED BOOLEAN
    ,DEL_FLAG BOOLEAN
    ,ITERATION INTEGER
    ,SALT TEXT
    ,UPDATE_ID TEXT
    ,UPDATE_PG TEXT
    ,UPDATE_DATE TIMESTAMP
}

ええ、カラムがの並びがぐちゃぐちゃですね。
プログラム視点では、DbContext経由でアクセスするのでクラス定義の通りに操作できるのであまり気になりません。
ですが、データベースの保守をしようとしたときにDBクライアント(DBeaverやA5SQL Mk2など)で見たときにはぐちゃぐちゃでたまったものではないですね。

Code First で生成されるテーブルのカラムを整える方法

どうやったらいい感じになるのだろう、と、[Column("COLUMN_NAME", Order = 1)]といったふうなことも試してみましたが、最も確実なのは以下の方法でした。
※ColumnAttibuteクラスのOrderプロパティは、キーが複数ある場合の優先順位を指定するもので、Code-FirstでDBを生成する際のカラム順を設定するものではありません。

  • Migrationコードの変更

EntityFrameworkCoreでは、dotnet efコマンドでデータベース作成コードの作成・実際のデータベース作成ができます。(.Net Framework EntityFrameworkではどうやるか分かっていないです)。

# このコマンドでデータベース作成コードの作成
dotnet ef migrations add <<Migration名>>

このコマンドで、Migrationsディレクトリ配下に以下のファイルができます。

ファイル名 説明
<<タイムスタンプ>>_<<Migration名>>.cs Migration名におけるテーブル定義ソース?
<<タイムスタンプ>>_<<Migration名>>_Designer.cs Migration名におけるカラム定義ソース?
<<DbContext名>>ModelSnapshot.cs DbContextのカラム定義ソース?

それぞれがなんの役割なのかはよく分かっていません。詳しい人教えて!

ですが、この中の<<タイムスタンプ>>\_<<Migration名>>.csUpメソッドの中に注目です。
この中で記述されている、migrationBuilder.CreateTableメソッドの引数にcolumnsがまさにテーブルのカラム順に影響しています。
ここの順序がちぐはぐな状態になっているため、最終的なデータベースのカラムもちぐはぐになります。
ここの並びを変更することで、期待したカラムの並びに変更することができました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

uGUIのImageにGlowっぽい輪郭線を付けるスクリプトの改良

初めに

UnityのuGUIのImageにOutlineスクリプトを適用すると、画像に輪郭線を付けることが出来るが、Glowの様なぼやけた輪郭線を付けるのは難しい。
対応策としてはこちらのコガネブログさんでも紹介されているが、以下のGlowImageというプロジェクト内にあるC#とShaderコードを使うという方法がある。
http://baba-s.hatenablog.com/entry/2017/12/31/211500
GlowImageのGithub
https://github.com/SylarLi/GlowImage

今回自分の勉強がてらこちらのコードを解読していた時に、「UnityのMask機能に対応していない事」と「シェーダーで最適化出来そうな所がある事」に気づいたので、改良してみた。

元コードのGlowImageで行っている事

箇条書きにすると以下のようになる
・Imageコンポーネントを継承したGlowImageクラスを作成
・GlowImageクラスのパラメーターから、既存Imageにアウトライン用の頂点とメッシュを追加する
・シェーダーでアウトラインを描画しつつガウシアン処理でぼかす
・最後に通常のImageを描画して行い終了

UnityのMask機能に対応させる

UnityのMask機能は、canvasRendererに登録されているマテリアルからマスク処理が適用されているコードを選別して処理を行っている。
既存コードではcanvasRendererに登録する処理が抜けていたため、canvasRendererをオーバーライドして、Image.materialにマテリアルを格納してからGraphicクラスのmaterialForRenderingを呼んで対応した

        public override Material materialForRendering
        {
            get
            {
                if(m_Material == null)
                {
                    material = new Material(Shader.Find("UI/GlowImageImprovement"));
                }
                // ここでパラメーター設定行う
                material.SetFloat("_OutlineSize", m_OutlineSize);
                material.SetColor("_OutlineColor", m_OutlineColor);
                material.SetFloat("_OutlineStrength", m_OutlineStrength);
                string format = "QUALITY_{0}";
                foreach (var item in System.Enum.GetNames(typeof(ImageOutlineQuality)))
                {
                    material.DisableKeyword(string.Format(format, item.ToUpper()));
                }
                material.EnableKeyword(string.Format(format, quality.ToString().ToUpper()));

                return base.materialForRendering;
            }
        }

ガウシアン処理の最適化

既存コードのシェーダーだと通常の平滑化処理のため重み(3x3, 7x7など)の数が増えるほど、ループ数が9, 49などかなり顕著に多くなっている。
画像処理のぼかし処理でよく使われるガウシアンブラーを使用する時、xとyの要素を切り離して処理できる場合ループ数を抑えることが出来る。
今回は以下のサイトを参考にコードを組んだ。

【Unity】【シェーダ】ガウス関数を使ってブラーを掛ける
http://light11.hatenadiary.com/entry/2018/05/20/010105
Unityでガウシアンブラーを実装する
http://edom18.hateblo.jp/entry/2018/12/30/171214

サンプルプロジェクト

コード全文は以下のプロジェクトを参照してください
※Windows10 + Unity2018.4.0f1で動作確認済み。
※ImageのTypeが「Simple」のみ対応
https://github.com/madoramu/GlowImageImprovement

実行結果
ss.png

補足

UnityのOutlineは頂点と頂点カラーを追加しているだけなので元画像も含めて1passで描画しているが、今回のコードはガウシアン処理の関係上2passで描画しなくてはいけないので、処理的には少し重いかも・・・

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む