Entity Framework 5.0复合外键到非主键 – 是否可能?
我在.net 4.5控制台应用程序中使用Entity Framework 5.0.0.0,我必须访问一个包含两个表的数据库,它们之间有外键关系,如下所示:
奇怪的是,外键在B(Almost1, Almost2)
和A(Almost1, Almost2)
而不是从B(AId)
到A(AId)
。 SQL服务器允许这样做,因为Almost1
和Almost2
组合是唯一的,并且都不可为空(至少在表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
列而是使Almost1
和Almost2
成为复合主键,那么我的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.AId
到A.AId
。
是的,我知道这有点奇怪 – 但是有可能在entity framework中处理这个问题吗?
如前所述,由于EF不支持唯一键和其他SQL对象。 我最终创建了一些脚本作为嵌入式资源,并将它们作为drop / create初始化程序的种子过程的一部分执行。
不确定这是否允许您在代码中的对象之间导航,但是在一个进程中更新数据库非常有效。