2013-06-27 43 views
2

我在.NET 4.5的控制台应用程序使用实体框架5.0.0.0和我有它两个表来访问数据库,象这样它们之间的外键关系:实体框架5.0复合外键非主键 - 是否有可能?

overview

奇数关于它的一点是,外键在B(Almost1, Almost2)A(Almost1, Almost2)之间,而不是从B(AId)A(AId)。这是由SQL服务器允许的,因为Almost1Almost2组合是唯一的,都不可为空(至少在表A上 - 它们是B它们是因为它是可选关系,但是是由)。

下面是一些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]) 

的事情是,它似乎没有被实体框架允许的 - 这样的话还是我只是没有正确定义我的模型?

这里是我的C#:

public class MyContext : DbContext 
{ 
    public MyContext(string connectionString) : base(connectionString) 
    { 
     MyAs = Set<A>(); 
     MyBs = Set<B>(); 
    } 

    public DbSet<A> MyAs { get; private set; } 
    public DbSet<B> MyBs { get; private set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     var aEntity = modelBuilder.Entity<A>(); 
     aEntity.ToTable("A"); 
     aEntity.HasKey(a => a.AId); 

     var bEntity = modelBuilder.Entity<B>(); 
     bEntity.ToTable("B"); 
     bEntity.HasKey(a => a.BId); 
     bEntity 
      .HasOptional(b => b.A) 
      .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<B> Bs { get; private set; } 
    public void AddB(B b) 
    { 
     if (b == null) throw new ArgumentNullException("b"); 
     if (Bs == null) Bs = new List<B>(); 
     if (!Bs.Contains(b)) Bs.Add(b); 
     b.A = this; 
    } 
} 

public class B 
{ 
    public int BId { get; set; } 
    public virtual A A { 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,差不多有' 无效。指定的列数必须与主键列的数量匹配。

如果我忽略了AId列,而是让Almost1Almost2复合主键,所以我OnModelCreating方法现在看起来是这样的:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    var aEntity = modelBuilder.Entity<A>(); 
    aEntity.ToTable("A"); 
    aEntity.HasKey(a => new { a.Almost1, a.Almost2 }); 
    aEntity.Ignore(a => a.AId); 

    var bEntity = modelBuilder.Entity<B>(); 
    bEntity.ToTable("B"); 
    bEntity.HasKey(a => a.BId); 
    bEntity 
     .HasOptional(b => b.A) 
     .WithMany(a => a.Bs) 
     .Map(m => m.MapKey("Almost1", "Almost2")); 
} 

它的工作原理,但我真的不希望这样做,因为还有一个表(我们称之为C),它与A以传统方式相关,具有AId列和外键从C.AIdA.AId

是的,这有点奇怪我知道 - 但是有可能在Entity Framework中处理这个问题吗?

+1

实体框架不支持唯一键,如果没有这些键,不幸的是它不能建模您的外键。 – hvd

+0

@hvd :-(好的,谢谢 – kmp

回答

1

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

不知道这是否允许您在代码中的对象之间进行导航,但它在数据库在一个进程中更新的过程中很好地工作。