LoginSignup
12
11

More than 5 years have passed since last update.

Entitiy Framework Code Firstでデフォルト値の設定

Last updated at Posted at 2016-12-05

Add-Migration前に初期値設定ができない

カラムにデフォルト値設定なんてよくあること。
しかしながらオプションにはそれららしいものが出てこない。
資料探して読んでみるもよくわからず。

なんでdefaultvalueが存在しているのに設定できないの???おかしくない???

設定にあるんだからできるはず。やってみましょう。

デフォルト値設定

http://stackoverflow.com/questions/19554050/entity-framework-6-code-first-default-value
defaultvalueがAdd-Migration前に設定できないのなんて先人が話題にしてないはずもなく。

雰囲気としては前回と変わらなそうな感じがしますね。
規約作る→modelBuilder.ConventionsにAddの流れで問題なさそうです。

ではまず規約を作りましょう。
今回はHasColumnAnnotationに設定します。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DefaultValueAttribute : Attribute
{
    public string DefaultValue { get; set; }
}

public class DefaultValueAttributeConvention
: PrimitivePropertyAttributeConfigurationConvention<DefaultValueAttribute>
{
    public override void Apply(ConventionPrimitivePropertyConfiguration configuration, DefaultValueAttribute attribute)
    {
        configuration.HasColumnAnnotation("DefaultValue", attribute.DefaultValue);
    }
}

そしてOnModelCreatingmodelBuilder.ConventionsにAddすると。

public class TestDataContext : DbContext
{
    public DbSet<testtable> testtable { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
        modelBuilder.Conventions.Add(new DefaultValueAttributeConvention());

        base.OnModelCreating(modelBuilder);
    }
}

ここからが前回と少し違うところ。
SqlServerMigrationSqlGeneratorを継承したSqlGeneratorを作ります。

internal class DefaultValueSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
    protected override void Generate(AddColumnOperation addColumnOperation)
    {
        SetAnnotatedColumn(addColumnOperation.Column);
        base.Generate(addColumnOperation);
    }

    protected override void Generate(AlterColumnOperation alterColumnOperation)
    {
        SetAnnotatedColumn(alterColumnOperation.Column);
        base.Generate(alterColumnOperation);
    }

    protected override void Generate(CreateTableOperation createTableOperation)
    {
        SetAnnotatedColumns(createTableOperation.Columns);
        base.Generate(createTableOperation);
    }

    protected override void Generate(AlterTableOperation alterTableOperation)
    {
        SetAnnotatedColumns(alterTableOperation.Columns);
        base.Generate(alterTableOperation);
    }

    private void SetAnnotatedColumn(ColumnModel col)
    {
        AnnotationValues values;
        if (col.Annotations.TryGetValue("DefaultValue", out values))
        {
            if (values.NewValue != null)
            {
                col.DefaultValueSql = (string)values.NewValue;
            }
            else
            {
                col.DefaultValueSql = null;
            }
        }
    }

    private void SetAnnotatedColumns(IEnumerable<ColumnModel> columns)
    {
        foreach (var column in columns)
        {
            SetAnnotatedColumn(column);
        }
    }
}

ここでは先ほどHasColumnAnnotationに設定したDefaultValueの情報を取得し、カラムのDefaultValue設定に反映しています。
いろいろ名称が被ってわかりづらいですね、申し訳ない。
この設定はConfiguration()で使います宣言しないと反映されないので、1文加えましょう。

public Configuration()
{
    AutomaticMigrationsEnabled = true;
    SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator());
}

ここまで来たら準備完了。
testtableでデフォルト値の設定をしてやりましょう。

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[Column(TypeName = "varchar")]
[StringLength(5)]
[DefaultValue(DefaultValue = "aaccc")]
public string varchartest { get; set; }

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue(DefaultValue = "4433")]
public int inttest { get; set; }

いざAdd-Migration

キャプチャ3.GIF

からのUpdate-Database

キャプチャ4.GIF

んんん?
"aaccc"はだめ?どういうことでしょ。
-Verboseをつけてもう一度Update-Databaseしてみます。

キャプチャ5.GIF

DEFAULTのあとのaacccが文字列じゃない!
ひゃー、なるほど。ここが原因ですね。
とりあえずこう出力されるということは数値ならば大丈夫な感じしますねえ。
aaccc55555と変更してUpdate-Databaseしてみると、エラー無く終了。
制約の下にこんなのが作成されていました。

キャプチャ6.GIF

ほうほう。では適当にinsertして大丈夫か確認してみましょう。

キャプチャ7.GIF

問題なさそうですね。数値の初期値設定完了です。

書き始めた時はAdd-Migration後に設定のDefaultValueに追加されているイメージだったんですが、AnnotationValuesに追加されることでも可能だったんですね。

文字列の場合

じゃあ文字列のデフォルト値設定はどうするの、と。
いろいろ試したら、思いの外簡単にできました。

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[Column(TypeName = "varchar")]
[StringLength(5)]
[DefaultValue(DefaultValue = "'aaccc'")]
public string varchartest { get; set; }

これでOKです。
DefaultValueに設定した文字列がそのままクエリに入るので、''から入れてやればこの通り。

キャプチャ8.GIF

キャプチャ9.GIF

うん、大丈夫そうです。

所感

実は昔これと同じことやろうとして断念したんですが、今回はできてよかったなあ。

一番大事なSqlServerMigrationSqlGeneratorが抜けてたので追記しました。

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11