【问题标题】:How to add a parent entity如何添加父实体
【发布时间】:2016-03-05 00:48:44
【问题描述】:

我的代码优先数据模型从标准 ApplicationUser 实体开始,其中包括邮政地址和帐单属性。现在我通过添加父 Account 实体扩展了我的模型:

  • 一个账号有多个ApplicationUser; ApplicationUser 现在具有相关帐户记录的不可为空的外键
  • 帐单和邮政地址现在与 Account 实体而非 ApplicationUser 实体相关联,因此相关属性已从 ApplicationUser 实体移至 Account 实体

为了更新数据库模式以合并新的父表,我会将每个现有的 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)?

【问题讨论】:

  • 以这种格式列出您期望的关系......1 account has many users1 user has 1 account...等
  • 您应该使用 SQL 为您的特定规则创建手动迁移脚本,然后使用包管理器控制台在 EF 中创建空迁移,并使用 Sql(@"<your migration code>"); 方法在此处插入此迁移脚本
  • @raderick 这就是问题的要点。我知道我需要在迁移脚本中添加“”注释。如果我能弄清楚如何使用与我将在 Seed 方法中使用的代码等效的东西,那么我就可以回家了,因为我可以遍历现有的用户记录并创建关联的帐户记录。但如果我仅限于使用 SQL,我不知道该怎么做。

标签: c# sql sql-server entity-framework


【解决方案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

抱歉格式化,如果我不添加评论标签,由于某种原因,它看起来有点搞砸了。

【讨论】:

  • 感谢一百万的 SQL 代码。我了解您如何使用临时列将 Account 行与其关联的 AspNetUser 行匹配。 (我自己永远不会想到这一点。)我没有得到的部分是“您的架构和数据迁移应该在不同的迁移类中”。为什么我不能在我在原始帖子中显示的迁移类中运行此 SQL,在添加 Accounts 表之后但在强制执行 FK 之前?
  • @Bob.at.SBS 从技术上讲可以,但我认为将架构更改和数据迁移拆分为单独的迁移总体上是一种好习惯。我还记得在同一张表上同时应用架构迁移和数据迁移时发生的一些问题,但不知道为什么会发生,我不得不将它们分成 2 个迁移。
猜你喜欢
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-06
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
  • 2014-04-05
相关资源
最近更新 更多