Я относительно новичок в подходе 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);
}
Любая помощь будет оценена по достоинству.
Хорошо, я сократил свой код до простейшей формы и следовал решению, предоставленному @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 будут нулевыми событиями, хотя в базе данных есть соответствующая запись.
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'.