Entity Framework 5.0复合外键到非主键 – 是否可能?

我在.net 4.5控制台应用程序中使用Entity Framework 5.0.0.0,我必须访问一个包含两个表的数据库,它们之间有外键关系,如下所示:

概观

奇怪的是,外键在B(Almost1, Almost2)A(Almost1, Almost2)而不是从B(AId)A(AId) 。 SQL服务器允许这样做,因为Almost1Almost2组合是唯一的,并且都不可为空(至少在表A上 – 在B它们是可选关系,但是由by表示)。

这是创建这种情况的一些SQL:

 CREATE TABLE [dbo].[A]( [AId] [int] IDENTITY(1,1) NOT NULL, [Almost1] [int] NOT NULL, [Almost2] [int] NOT NULL, CONSTRAINT [PK_A] PRIMARY KEY CLUSTERED ( [AId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], CONSTRAINT [A_Constraint] UNIQUE NONCLUSTERED ( [Almost1] ASC, [Almost2] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] CREATE TABLE [dbo].[B]( [BId] [int] IDENTITY(1,1) NOT NULL, [Almost1] [int] NULL, [Almost2] [int] NULL, CONSTRAINT [PK_B] PRIMARY KEY CLUSTERED ( [BId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] ALTER TABLE [dbo].[B] ADD CONSTRAINT [FK_A_B] FOREIGN KEY([Almost1], [Almost2]) REFERENCES [dbo].[A] ([Almost1], [Almost2]) 

事实是,似乎entity framework不允许 – 这是这种情况还是我没有正确定义我的模型?

这是我的c#:

 public class MyContext : DbContext { public MyContext(string connectionString) : base(connectionString) { MyAs = Set(); MyBs = Set(); } public DbSet MyAs { get; private set; } public DbSet MyBs { get; private set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { var aEntity = modelBuilder.Entity(); aEntity.ToTable("A"); aEntity.HasKey(a => a.AId); var bEntity = modelBuilder.Entity(); bEntity.ToTable("B"); bEntity.HasKey(a => a.BId); bEntity .HasOptional(b => bA) .WithMany(a => a.Bs) .Map(m => m.MapKey("Almost1", "Almost2")); } } public class A { public int AId { get; set; } public int Almost1 { get; set; } public int Almost2 { get; set; } public virtual ICollection Bs { get; private set; } public void AddB(B b) { if (b == null) throw new ArgumentNullException("b"); if (Bs == null) Bs = new List(); if (!Bs.Contains(b)) Bs.Add(b); bA = this; } } public class B { public int BId { get; set; } public virtual AA { get; set; } } class Program { static void Main() { using (var ctx = new MyContext(@"connection string")) { ctx.MyAs.Add(new A { Almost1 = 1, Almost2 = 1 }); ctx.SaveChanges(); } } } 

它抛出一个InvalidOperationException

指定的关联外键列’Almost1,Almost2’无效。 指定的列数必须与主键列的数量匹配。

如果我忽略了AId列而是使Almost1Almost2成为复合主键,那么我的OnModelCreating方法现在看起来像这样:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { var aEntity = modelBuilder.Entity(); aEntity.ToTable("A"); aEntity.HasKey(a => new { a.Almost1, a.Almost2 }); aEntity.Ignore(a => a.AId); var bEntity = modelBuilder.Entity(); bEntity.ToTable("B"); bEntity.HasKey(a => a.BId); bEntity .HasOptional(b => bA) .WithMany(a => a.Bs) .Map(m => m.MapKey("Almost1", "Almost2")); } 

它可以工作,但我真的不想这样做,因为还有一个表(我们称之为C ),它以传统的方式与A ,有一个AId列,外键是从C.AIdA.AId

是的,我知道这有点奇怪 – 但是有可能在entity framework中处理这个问题吗?

如前所述,由于EF不支持唯一键和其他SQL对象。 我最终创建了一些脚本作为嵌入式资源,并将它们作为drop / create初始化程序的种子过程的一部分执行。

不确定这是否允许您在代码中的对象之间导航,但是在一个进程中更新数据库非常有效。