сначала литерал или константа как часть составного ключа в коде EF

Я относительно новичок в подходе Code First к Entity Framework. Я уже давно использую подход Database First, но Code First, кажется, лучше подходит для приложения, которое я сейчас разрабатываю. Я работаю с существующей базой данных MS SQL, и мне не разрешено вносить какие-либо изменения в базу данных. Причина, по которой я использую Code First, заключается в том, что Fluent API позволяет мне динамически назначать имя таблицы классу.

Тем не менее, у меня есть затруднительное положение, когда мне нужно назначить связь между двумя таблицами. Одна таблица, 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; }

}

Другая таблица, Invoices, должна быть связана с таблицей 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», так и для свойства «Условия». Однако я не уверен, как это сделать в отношении части CodeType составного ключа. Для кодов "через" тип кода должен быть "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

Хорошо, я сократил свой код до простейшей формы и следовал решению, предоставленному @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();

error 3032: Problem in mapping fragments starting at line 28:Condition member 'ArCode.cod_typ' with a condition other than 'IsNull=False' is mapped. Either remove the condition on ArCode.cod_typ or remove it from the mapping.

Если я удалю столбец «CodeType» из класса ArCode и изменю все ссылки «CodeType» на имя столбца базы данных «cod _type» в событии OnModelCreating,то оператор выше выполняется без ошибок. Однако и invoice.ShipVia, и invoice.Terms будут нулевыми событиями, хотя в базе данных есть соответствующая запись.

Обновление #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 - Invalid column name 'ShipVia_Code'. Invalid column name 'Terms_Code'.

7
задан Keenan Marshall 26 July 2012 в 19:33
поделиться