Kee*_*all 7 entity-framework ef-code-first entity-framework-4.1
我对实体框架的Code First方法相对较新.我已经使用了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; }
}
Run Code Online (Sandbox Code Playgroud)
另一个表,Invoices,需要与ArCodes表关联"ship via"代码和"terms"代码.
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; }
}
Run Code Online (Sandbox Code Playgroud)
我想为"ShipVia"属性和"Terms"属性设置关系.但是,我不知道如何对复合键的CodeType部分这样做.对于"发货通过"代码,代码类型应为"S",代码"条款"代码,代码类型应为"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);
}
Run Code Online (Sandbox Code Playgroud)
任何帮助,将不胜感激.
好吧,我把代码简化为最简单的形式,然后按照@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") {
}
}
Run Code Online (Sandbox Code Playgroud)
但是,以下代码返回错误:
PbsContext context = new PbsContext();
var invoice = context.Invoices.OrderByDescending(r => r.InvoiceDate).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
错误3032:从第28行开始映射片段时出现问题:映射了条件成员'ArCode.cod_typ',其条件不是'IsNull = False'.删除ArCode.cod_typ上的条件或从映射中删除它.
如果我从ArCode类中删除"CodeType"列并将所有"CodeType"引用更改为OnModelCreating事件中"cod_typ"的数据库列名,则上述语句将无错误地执行.但是,invoice.ShipVia和invoice.Terms都是null事件,尽管数据库中有匹配的记录.
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") {
}
}
Run Code Online (Sandbox Code Playgroud)
现在,以下代码返回错误:
PbsContext context = new PbsContext();
var invoice = context.Invoices.OrderByDescending(r => r.InvoiceDate).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
EntityCommandExecutionException - 无效的列名称"ShipVia_Code".列名称"Terms_Code"无效.
你想要的对于EF来说是不可能的。ArCode有一个复合键,因此与它的任何关联都必须使用两个属性。这意味着Invoice您需要四个属性(两对)来引用这两个ArCode对象。但其中两个属性(用于 的属性CodeType)未由数据库中的列备份,因此 EF 无法映射它们。
但是……有一种方法可以帮助你。您可以从中创建两个派生类,ArCode并Invoice通过单属性关联来引用它们。但随后您必须从模型本身转移并通过定义单个键来愚弄 EF:
public abstract class ArCode { ... } // abstract!
public class TermsCode : ArCode { }
public class ShipViaCode : ArCode { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Invoice>().ToTable("IHSHDR");
modelBuilder.Entity<Invoice>().HasOptional(i => i.Terms).WithOptionalDependent().Map(m => m.MapKey("terms_cod"));
modelBuilder.Entity<Invoice>().HasOptional(i => i.ShipVia).WithOptionalDependent().Map(m => m.MapKey("shp_via_cod"));
modelBuilder.Entity<ArCode>().HasKey(a => a.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 class Invoice
{
[Column("pi_hist_hdr_invc_no"), Key]
public int InvoiceNumber { get; set; }
public ShipViaCode ShipVia { get; set; }
public TermsCode Terms { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您不必ARCODS通过 EF 插入记录,这可能适合您。它不允许您插入具有相同Codes 的记录,尽管数据库允许这样做。但我预计内容会ARCODS相当稳定,也许用脚本来填充它就足够了。
| 归档时间: |
|
| 查看次数: |
2196 次 |
| 最近记录: |