在下面的代码中,我首先使用 EF 代码来设置我的数据库模型。
CaseCommunication 实体有一个复合键,包括一个 Id 列。如果我让 EF 完成这项工作,它会尝试将此列用作另一个实体的 FK,尽管有 Many() 规范:
HasRequired(x => x.Case).WithMany(x => x.Communications);
HasOptional(x => x.FirstReadBy).WithMany();
要获得正确的模型,我必须明确设置 FK(请阅读代码中的注释)。
HasRequired(x => x.Case).WithMany(x => x.Communications).Map(x => x.MapKey("Case_Id"));
HasOptional(x => x.FirstReadBy).WithMany().Map(x => x.MapKey("FirstReadBy_Id"));
如果我不使用复合键,那么在不使用 Map() 的情况下一切正常。
我的问题是: EF 的逻辑是什么?或者换一种说法,我错过了什么?
using System;
using System.Linq;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data.Entity.ModelConfiguration;
using System.Data.Objects.SqlClient;
using System.ComponentModel.DataAnnotations.Schema;
namespace testef {
//Model
public partial class Case {
public Case() {
Communications = new List<CaseCommunication>();
}
public Int32 Id { get; set; }
public virtual ICollection<CaseCommunication> Communications { get; set; }
}
public class CaseCommunication {
public String CComType { get; set; }
public Int32 Id { get; set; }
public virtual Case Case { get; set; }
public virtual User FirstReadBy { get; set; }
}
public class User {
public Int32 Id { get; set; }
}
//Configuration for CObj
public class UserEFCFConfiguration : EntityTypeConfiguration<User> {
public UserEFCFConfiguration()
: base() {
ToTable("Users", "dbo");
HasKey(x => x.Id);
Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class CaseEFCFConfiguration : EntityTypeConfiguration<Case> {
public CaseEFCFConfiguration()
: base() {
ToTable("Cases", "dbo");
HasKey(x => x.Id);
Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class CaseCommunicationEFCFConfiguration : EntityTypeConfiguration<CaseCommunication> {
public CaseCommunicationEFCFConfiguration()
: base() {
ToTable("VCaseCommunications", "dbo");
Property(x => x.CComType).HasColumnType("char").HasMaxLength(2);
HasKey(x => new { x.CComType, x.Id });
// OK
HasRequired(x => x.Case).WithMany(x => x.Communications).Map(x => x.MapKey("Case_Id"));
HasOptional(x => x.FirstReadBy).WithMany().Map(x => x.MapKey("FirstReadBy_Id"));
// KO
//HasRequired(x => x.Case).WithMany(x => x.Communications);
//HasOptional(x => x.FirstReadBy).WithMany()
//EF tries to use the x.Id as FK for both Case and FirstReadBy
//For FirstReadBy this leads to a Model error as x.Id is not nullable
//But in each case I can't understand how EF expect to give the many relation by using a part of the PK as FK
// OK
//HasKey(x => x.Id);
//HasRequired(x => x.Case).WithMany(x => x.Communications);
//HasOptional(x => x.FirstReadBy).WithMany()
}
}
public class TestEFContext : DbContext {
public IDbSet<Case> Cases { get; set; }
public TestEFContext(String cs)
: base(cs) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new UserEFCFConfiguration());
modelBuilder.Configurations.Add(new CaseEFCFConfiguration());
modelBuilder.Configurations.Add(new CaseCommunicationEFCFConfiguration());
}
}
class Program {
static void Main(String[] args) {
String cs = @"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext c = new TestEFContext(cs)) {
Console.WriteLine(c.Cases.Count());
}
}
}
}