8

私は、Entity Framework への Code First アプローチに比較的慣れていません。しばらくデータベース ファーストのアプローチを使用してきましたが、現在開発中のアプリケーションにはコード ファーストの方が適しているようです。私は既存の MS SQL データベースを使用していますが、データベースに変更を加えることはできません。Code First を使用する理由は、Fluent API を使用すると、テーブル名をクラスに動的に割り当てることができるからです。

そうは言っても、2 つのテーブル間の関係を割り当てる必要があるという苦境があります。1 つのテーブル ArCodes には、CodeType と Code (両方とも文字列) で構成される複合キーがあります。CodeType 列はコードの種類を決定し、Code 列はコードの種類に固有の識別子です。

public class ArCode {

    [Column("cod_typ", Order = 0), Key]
    public string CodeType { get; set; }

    [Column("ar_cod", Order = 1), Key]
    public string Code { get; set; }

    [Column("desc")]
    public string Description { get; set; }

}

もう 1 つのテーブル Invoices は、「ship via」コードと「terms」コードの両方について、ArCodes テーブルとの関係を持つ必要があります。

public class Invoice {
    [Column("pi_hist_hdr_invc_no"), Key]
    public int InvoiceNumber { get; set; }

    [Column("shp_via_cod")]
    public string ShipViaCode { get; set; }

    public ArCode ShipVia { get; set; }

    [Column("terms_cod")]
    public string TermsCode { get; set; }

    public ArCode Terms { get; set; }

}

「ShipVia」プロパティと「Terms」プロパティの両方の関係をセットアップしたいと考えています。ただし、複合キーの CodeType 部分に関しては、その方法がわかりません。「ship via」コードの場合、Code Type は「S」である必要があり、コード「terms」コードの場合、コード タイプは「T」である必要があります。

DB Context で次のことを試しましたが、うまくいきませんでした:

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        // setup the table names
        modelBuilder.Entity<ArCode>().ToTable("ARCODS" + CompanyCode);
        modelBuilder.Entity<Invoice>().ToTable("IHSHDR" + CompanyCode);

        //
        // setup the relationships
        //

        // 1 Invoice <--> 0-1 Ship Via AR Codes
        modelBuilder.Entity<Invoice>()
            .HasOptional(invoice => invoice.ShipVia)
            .WithMany()
            .HasForeignKey(invoice => new { TheType = "S", invoice.ShipViaCode })
            ;

        base.OnModelCreating(modelBuilder);
    }

どんな助けでも大歓迎です。

更新 #1

OK、コードを最も単純な形式に減らし、@GertArnold が提供するソリューションに従いました。

public abstract class ArCode {

    [Column("cod_typ")]
    public string CodeType { get; set; }

    [Column("ar_cod")]
    public string Code { get; set; }

    [Column("terms_desc")]
    public string TermsDescription { get; set; }

    [Column("terms_typ")]
    public string TermsType { get; set; }

    [Column("shp_via_desc")]
    public string ShipViaDescription { get; set; }

    [Column("tax_desc")]
    public string TaxDescription { get; set; }

}

public class TermsCode : ArCode { }
public class ShipViaCode : ArCode { }

public class Invoice {
    [Column("pi_hist_hdr_invc_no"), Key]
    public int InvoiceNumber { get; set; }

    [Column("hdr_invc_dat")]
    public DateTime InvoiceDate { get; set; }

    [Column("shp_via_cod")]
    public string ShipViaCode { get; set; }

    public ShipViaCode ShipVia { get; set; }

    [Column("terms_cod")]
    public string TermsCode { get; set; }

    public TermsCode Terms { get; set; }

    public Invoice() {
    }

}

public class PbsContext : DbContext {

    public DbSet<Invoice> Invoices { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {

        modelBuilder.Entity<Invoice>().ToTable("IHSHDR");

        modelBuilder.Entity<ArCode>().HasKey(r => r.Code).ToTable("ARCODS");

        modelBuilder.Entity<TermsCode>().Map(m => m.Requires("CodeType")
               .HasValue("T").HasColumnType("varchar").HasMaxLength(1).IsRequired())
               .ToTable("ARCODS");
        modelBuilder.Entity<ShipViaCode>().Map(m => m.Requires("CodeType")
               .HasValue("S").HasColumnType("varchar").HasMaxLength(1).IsRequired())
               .ToTable("ARCODS");

        base.OnModelCreating(modelBuilder);
    }

    public PbsContext()
        : base("name=PbsDatabase") {
    }
}

ただし、次のコードはエラーを返します。

PbsContext context = new PbsContext();
var invoice = context.Invoices.OrderByDescending(r => r.InvoiceDate).FirstOrDefault();

エラー 3032: 28 行目から始まるフラグメントのマッピングに問題があります: 'IsNull=False' 以外の条件を持つ条件メンバー 'ArCode.cod_typ' がマップされています。ArCode.cod_typ の条件を削除するか、マッピングから削除してください。

ArCode クラスから「CodeType」列を削除し、OnModelCreating イベント内の「cod_typ」というデータベース列名へのすべての「CodeType」参照を変更すると、上記のステートメントはエラーなしで実行されます。ただし、データベースに一致するレコードがあっても、invoice.ShipVia と Invoice.Terms は両方とも null イベントになります。

アップデート #2

public abstract class ArCode {

    [Column("ar_cod")]
    public string Code { get; set; }

    [Column("terms_desc")]
    public string TermsDescription { get; set; }

    [Column("terms_typ")]
    public string TermsType { get; set; }

    [Column("shp_via_desc")]
    public string ShipViaDescription { get; set; }

    [Column("tax_desc")]
    public string TaxDescription { get; set; }

}

public class TermsCode : ArCode { }
public class ShipViaCode : ArCode { }

public class Invoice {
    [Column("pi_hist_hdr_invc_no"), Key]
    public int InvoiceNumber { get; set; }

    [Column("hdr_invc_dat")]
    public DateTime InvoiceDate { get; set; }

    [Column("shp_via_cod")]
    public ShipViaCode ShipVia { get; set; }

    [Column("terms_cod")]
    public TermsCode Terms { get; set; }

    public Invoice() {
    }

}

public class PbsContext : DbContext {

    public DbSet<Invoice> Invoices { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {

        modelBuilder.Entity<Invoice>().ToTable("IHSHDR");

        modelBuilder.Entity<ArCode>().HasKey(r => r.Code).ToTable("ARCODS");

        modelBuilder.Entity<TermsCode>().Map(m => m.Requires("CodeType")
               .HasValue("T").HasColumnType("varchar").HasMaxLength(1).IsRequired())
               .ToTable("ARCODS");
        modelBuilder.Entity<ShipViaCode>().Map(m => m.Requires("CodeType")
               .HasValue("S").HasColumnType("varchar").HasMaxLength(1).IsRequired())
               .ToTable("ARCODS");

        base.OnModelCreating(modelBuilder);
    }

    public PbsContext()
        : base("name=PbsDatabase") {
    }
}

ここで、次のコードはエラーを返します。

PbsContext context = new PbsContext();
var invoice = context.Invoices.OrderByDescending(r => r.InvoiceDate).FirstOrDefault();

EntityCommandExecutionException - 列名 'ShipVia_Code' が無効です。列名「Terms_Code」が無効です。

4

1 に答える 1