2016-03-05 72 views
1

我的代碼優先數據模型以標準ApplicationUser實體開始,其中包括郵政地址和帳單屬性。現在我通過添加父項來擴展我的模型Account實體:如何添加父實體

  • 一個帳戶有許多ApplicationUsers; ApplicationUser現在對相關帳戶記錄具有不可空的外鍵
  • 帳單和郵政地址現在與帳戶實體相關聯,而不是與ApplicationUser實體關聯,因此相關屬性已從ApplicationUser實體移至帳戶實體

爲了更新數據庫模式以合併新的父表,我將爲每個現有的ApplicationUser分配一個新創建的Account。所以,我需要爲每個現有ApplicationUser做兩件事情:

  1. 我需要創建一個新帳戶那一行的結算和郵寄地址字段值從ApplicationUser行採取。
  2. 我需要將ApplicationUser.AccountId外鍵字段設置爲新創建的Account行的主鍵值。

請注意,我的代碼託管在Azure上,並且數據位於Azure SQL Server中。

腳手架遷移代碼如下所示(大大簡化)

// Create the new Accounts table 
CreateTable(
    "dbo.Accounts", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      BillingInfo = c.String(), 
      PostalAddress = c.String(), 
     }) 
    .PrimaryKey(t => t.Id); 

// Add the new FK column 
AddColumn("dbo.AspNetUsers", "AccountId", c => c.Int(nullable: false)); 
CreateIndex("dbo.AspNetUsers", "AccountId"); 

// Before we add the AspNetUsers.AccountId foreign key, we need to populate 
// the Accounts table (one Account for each User) 
Sql("some SQL command(s)") 

// Make the column a foreign key 
AddForeignKey("dbo.AspNetUsers", "AccountId", "dbo.Accounts", "Id", cascadeDelete: true); 

// Deleted fields 
DropColumn("dbo.AspNetUsers", "BillingInfo"); 
DropColumn("dbo.AspNetUsers", "PostalAddress"); 

至於我可以告訴大家,我的創建或修改數據唯一的選擇是使用Sql()方法(或SqlFile()SqlResource())如上面的代碼所示。

如果我僅限於使用SQL,那麼什麼樣的SQL命令可以完成此任務?我可以在一個大的ol命令中加入某種JOIN(對於尚不存在的記錄),還是需要求助於SQL循環(as shown in this article)?

+0

列出你在此格式期望的關係....'1帳戶有很多users','1用戶1個account' ...等 –

+0

你應該使用SQL對特定規則的創建手動遷移腳本,然後使用包管理器控制檯在EF中創建空遷移,並使用'Sql(@「<您的遷移代碼>」)插入此遷移腳本;'方法 –

+0

@raderick這是問題的要點。我知道我需要在遷移腳本中添加「<這裏做點什麼>」評論。如果我能弄清楚如何使用與我在Seed方法中使用的代碼等效的東西,那麼我可以免費入住,因爲我可以遍歷現有的用戶記錄並創建關聯的帳戶記錄。但是如果我僅限於使用SQL,我不知道如何去做。 –

回答

1

核心想法是很簡單:

  1. 你的架構和數據遷移應該在不同的移民類

  2. 對於遷移,你需要對你的側引入臨時僞FK列插入和遷移使用此列的數據。高水平的想法看起來大約是這樣的:

ALTER TABLE [dbo].[Accounts] ADD [_Temp_AspNetUserId] int; 
GO 

/*insert data into accounts with reference from AspNetUsers*/ 
INSERT INTO [dbo].[Accounts] (BillingInfo, PostalAddress, _Temp_AspNetUserId) 
SELECT user.BillingInfo, user.PostalAddress, user.Id 
FROM [dbo].[AspNetUsers] user 

/*update original foreign key relationship for [AspNetUsers] table*/ 
UPDATE [dbo].[AspNetUsers] 
SET AccountId = [dbo].[AspNetUsers].Id 
FROM [dbo].[Accounts] 
WHERE [dbo].[Accounts]._Temp_AspNetUserId = [dbo].[AspNetUsers].Id 

/*drop temporary column*/ 
ALTER TABLE [dbo].[Accounts] DROP COLUMN [_Temp_AspNetUserId]; 
GO 

對不起格式,由於某種原因,它看起來有點搞砸了,如果我不加註釋標記。

+0

非常感謝SQL代碼。我瞭解如何使用臨時列來將帳戶行與其關聯的AspNetUser行進行匹配。 (我從來不會想到這一點。)我沒有得到的部分是「你的模式和數據遷移應該在不同的遷移類中」。爲什麼我不能在遷移類中運行這個SQL,我在原來的帖子中顯示的遷移類中,在添加Accounts表之後但在FK執行之前? –

+0

@ Bob.at.SBS在技術上可以,但我認爲將模式更改和數據遷移分解爲單獨的遷移是一種很好的做法。我還記得將同一個表上的數據遷移一起應用模式遷移時發生的一些問題,但不知道它們爲什麼發生,我不得不將它們拆分爲2個遷移。 –