2013-06-27 62 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初始化程序的種子進程的一部分執行。

不知道這是否允許您在代碼中的對象之間進行導航,但它在數據庫在一個進程中更新的過程中很好地工作。