28452

[code]

    public class Hoge1
    {
        public int Id { get; set; }
        public Hoge2 Hoge2 { get; set; }
    }
    
    [ComplexType]
    public class Hoge2
    {
        public string Text { get; set; }
        public Hoge3 Hoge3A { get; set; }
        public Hoge3 Hoge3B { get; set; }
    }
    
    [ComplexType]
    public class Hoge3
    {
        public string Value1 { get; set; }
        public string Value2 { get; set; }
        public string Value3 { get; set; }
        ・・・
        public string Value99 { get; set; }
    }
    
[/code]

コードファーストでテーブルを作成すると以下のような列名で生成されます。

[code]

    [Hoge2_Text]
    [Hoge2_Hoge3A_Value1]
    [Hoge2_Hoge3A_Value2]
    [Hoge2_Hoge3A_Value3]
    ・・・
    [Hoge2_Hoge3A_Value99]
    [Hoge2_Hoge3B_Value1]
    [Hoge2_Hoge3B_Value2]
    [Hoge2_Hoge3B_Value3]
    ・・・
    [Hoge2_Hoge3B_Value99]
    
[/code]

これを

[code]

    [Text]
    [Hoge3A_Value1]
    [Hoge3A_Value2]
    [Hoge3A_Value3]
    ・・・
    [Hoge3A_Value99]
    [Hoge3B_Value1]
    [Hoge3B_Value2]
    [Hoge3B_Value3]
    ・・・
    [Hoge3B_Value99]
    
[/code]

のような列名にしたいです。

[code]

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Hoge1>().Property(entity => entity.Hoge2.Text).HasColumnName("Text");
        modelBuilder.Entity<Hoge1>().Property(entity => entity.Hoge2.Hoge3A.Value1).HasColumnName("Hoge3A_Value1");
        modelBuilder.Entity<Hoge1>().Property(entity => entity.Hoge2.Hoge3A.Value2).HasColumnName("Hoge3A_Value2");
        modelBuilder.Entity<Hoge1>().Property(entity => entity.Hoge2.Hoge3A.Value3).HasColumnName("Hoge3A_Value3");
        ・・・
        modelBuilder.Entity<Hoge1>().Property(entity => entity.Hoge2.Hoge3B.Value99).HasColumnName("Hoge3B_Value99");
    
[/code]

と書けば実現できるところまでは理解できましたが、もっとシンプルに記述する方法はあるでしょうか？  
（クラス階層の中間にある Hoge2 を列名のプレフィクスから除外したい）


CC BY-SA 3.0
2016-08-23T12:19:26.093
28450
2016-08-23T14:17:46.673
2016-08-23T12:57:41.713
3925
3925
question
c# entity-framework
複合型プロパティの列名を制御したい


`Column`属性でしょうか。

[code]

    [ComplexType]
    public class Hoge3
    {
        [Column("Hoge3_Value1")]
        public string Value1 { get; set; }
        [Column("Hoge3_Value2")]
        public string Value2 { get; set; }
        [Column("Hoge3_Value3")]
        public string Value3 { get; set; }
        ・・・
        [Column("Hoge3_Value99")]
        public string Value99 { get; set; }
    }
    
[/code]


CC BY-SA 3.0
2016-08-23T12:46:55.313
28451
2016-08-23T12:46:55.313
4236
28450
answer


`Hoge1`に`Hoge3A`, `Hoge3B`を直接定義するのが簡潔だと思いますが、`OnModelCreating`での解決も一応可能です。  
例えば下記は`DbModelBuilder`のジェネリックメンバーをリフレクションで実行しています。

[code]

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Hoge1エンティティの構成を取得します。
        var etc = modelBuilder.Entity<Hoge1>();
        var etcType = etc.GetType();
    
        // Hoge1.Hoge2へのラムダ式
        Expression<Func<Hoge1, Hoge2>> hoge2Expression = e => e.Hoge2;
    
        // Hoge2のプロパティの繰り返し処理
        foreach (var cp in typeof(Hoge2).GetProperties())
        {
            // Hoge3型プロパティのみを対象とします。
            if (cp.PropertyType == typeof(Hoge3))
            {
                // Hoge3のプロパティの繰り返し処理
                foreach (var pp in typeof(Hoge3).GetProperties())
                {
                    // Hoge3のプロパティを構成するためのメソッドを取得します。
                    var propMethod = etcType.GetMethod(
                                        nameof(etc.Property),
                                        new[]
                                        {
                                            typeof(Expression<>).MakeGenericType(
                                                typeof(Func<,>).MakeGenericType(
                                                    typeof(Hoge1),
                                                    pp.PropertyType))
                                        });
    
                    // Hoge1からHoge3のプロパティを取得するラムダ式を作成します。
                    var newBody = Expression.Property(Expression.Property(hoge2Expression.Body, cp), pp);
                    var lambda = Expression.Lambda(newBody, hoge2Expression.Parameters);
    
                    // プロパティの構成を取得します。
                    var ppc = (PrimitivePropertyConfiguration)propMethod.Invoke(etc, new[] { lambda });
    
                    // 列名を指定します。
                    ppc.HasColumnName($"{cp.Name}_{pp.Name}");
                }
            }
        }
    }
    
[/code]

しかし`DbModelBuilder`は情報の設定のみを意図しているため、エンティティ型で構成したモデルの情報が全く取得できません。これは`Convention`などの他のEntity
Frameworkの変更ポイントでも同じです。ですので、上記のコードのように`System.Type`や`PropertyInfo`を参照して処理を行わないといけません。

ですので、`Hoge2`を排除できるような設計に変えた方が良いと思います。もし`Hoge2`がDBに関係のない場面で必要なのであれば、以下のようにインターフェイスを利用したり、

[code]

    public class Hoge1 : IHoge2
    {
        public int Id { get; set; }
        public string Text { get; set; }
        public Hoge3 Hoge3A { get; set; }
        public Hoge3 Hoge3B { get; set; }
    }
    
[/code]

マップされないプロパティをすることもできます。

[code]

    public class Hoge1
    {
        public int Id { get; set; }
        public string Text { get; set; }
        public Hoge3 Hoge3A { get; set; }
        public Hoge3 Hoge3B { get; set; }
    
        [NotMapped]
        public Hoge2 Hoge2 => new Hoge2()
        {
            Text = Text,
            Hoge3A = Hoge3A,
            Hoge3B = Hoge3B,
        };
    }
    
[/code]


CC BY-SA 3.0
2016-08-23T14:17:46.673
28452
2016-08-23T14:17:46.673
5750
28450
answer