gpt4 book ai didi

c# - CUD : What is the purpose of the two SELECT statements in a scaffolded Insert stored procedure? 的存储过程

转载 作者:行者123 更新时间:2023-11-30 16:52:52 24 4
gpt4 key购买 nike

浏览 Tom Dykstra 的 Getting Started with Entity Framework 6 Code First using MVC 5教程,part 9涵盖如何设置 EF6 以使用 CUD 的存储过程。

当通过包管理器控制台添加 DepartmentSP 迁移时,会自动生成以下 CreateStoredProcedure() 调用以创建 Department_Insert 存储过程:

CreateStoredProcedure(
"dbo.Department_Insert",
p => new
{
Name = p.String(maxLength: 50),
Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
StartDate = p.DateTime(),
InstructorID = p.Int(),
},
body:
@"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID])
VALUES (@Name, @Budget, @StartDate, @InstructorID)

DECLARE @DepartmentID int
SELECT @DepartmentID = [DepartmentID]
FROM [dbo].[Department]
WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity()

SELECT t0.[DepartmentID]
FROM [dbo].[Department] AS t0
WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID"
);

为什么自动生成的存储过程中有两条SELECT语句?

我测试了以下简化:

CreateStoredProcedure(
"dbo.Department_Insert",
p => new
{
Name = p.String(maxLength: 50),
Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
StartDate = p.DateTime(),
InstructorID = p.Int(),
},
body:
@"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID])
VALUES (@Name, @Budget, @StartDate, @InstructorID)

SELECT t0.[DepartmentID]
FROM [dbo].[Department] AS t0
WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = scope_identity()"
);

.. 这似乎工作正常,但我可能遗漏了一些东西。

我已阅读 What's New in Entity Framework 6 (Plus How To Upgrade!)Code First Insert/Update/Delete Stored Procedure Mapping spec .另外,我查看了 EF6 git 提交历史并找到了 commit 1911dc7 ,这是在迁移中启用存储过程脚手架的第一部分。

最佳答案

我想我明白了。

生成 Insert 存储过程主体的代码可在 src/EntityFramework.SqlServer/SqlGen/DmlFunctionSqlGenerator.cs 中的 DmlFunctionSqlGenerator.GenerateInsert() 方法中找到。 .

相关代码如下:

// Part 1
sql.Append(
DmlSqlGenerator.GenerateInsertSql(
firstCommandTree,
_sqlGenerator,
out _,
generateReturningSql: false,
createParameters: false));

sql.AppendLine();

var firstTable
= (EntityType)((DbScanExpression)firstCommandTree.Target.Expression).Target.ElementType;

// Part 2
sql.Append(IntroduceRequiredLocalVariables(firstTable, firstCommandTree));

// Part 3
foreach (var commandTree in commandTrees.Skip(1))
{
sql.Append(
DmlSqlGenerator.GenerateInsertSql(
commandTree,
_sqlGenerator,
out _,
generateReturningSql: false,
createParameters: false));

sql.AppendLine();
}

var returningCommandTrees
= commandTrees
.Where(ct => ct.Returning != null)
.ToList();

// Part 4
if (returningCommandTrees.Any())
{
//...

第 1 部分生成 INSERT 语句。第 2 部分生成 DECLARE 行和第一个 SELECT 语句。第 4 部分生成第二个 SELECT 语句。

在 Contoso University 示例中,Department 实体类是一个简单的模型类。似乎在这种情况下,传递给 DmlFunctionSqlGenerator.GenerateInsert() 的 commandTrees 集合仅包含一个 DbInsertCommandTree 元素。因此,实际上跳过了第 3 部分中的 foreach 循环。

在其他情况下,commandTrees 集合中可以有多个DbInsertCommandTree 元素,例如当一个实体类扩展另一个实体类和Table per Type inheritance mapping strategy 时用来。例如:

[Table("SpecialOrder")]
public class SpecialOrder
{
public int SpecialOrderId { get; set; }

public DateTime Date { get; set; }

public int Status { get; set; }
}

[Table("ExtraSpecialOrder")]
public class ExtraSpecialOrder : SpecialOrder
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ExtraSpecialOrderId { get; set; }

public string ExtraNotes { get; set; }
}

ExtraSpecialOrder 实体的脚手架插入存储过程是:

CreateStoredProcedure(
"dbo.ExtraSpecialOrder_Insert",
p => new
{
Date = p.DateTime(),
Status = p.Int(),
ExtraNotes = p.String(),
},
body:
@"INSERT [dbo].[SpecialOrder]([Date], [Status])
VALUES (@Date, @Status)

DECLARE @SpecialOrderId int
SELECT @SpecialOrderId = [SpecialOrderId]
FROM [dbo].[SpecialOrder]
WHERE @@ROWCOUNT > 0 AND [SpecialOrderId] = scope_identity()

INSERT [dbo].[ExtraSpecialOrder]([SpecialOrderId], [ExtraNotes])
VALUES (@SpecialOrderId, @ExtraNotes)

SELECT t0.[SpecialOrderId], t1.[ExtraSpecialOrderId]
FROM [dbo].[SpecialOrder] AS t0
JOIN [dbo].[ExtraSpecialOrder] AS t1 ON t1.[SpecialOrderId] = t0.[SpecialOrderId]
WHERE @@ROWCOUNT > 0 AND t0.[SpecialOrderId] = @SpecialOrderId"
);

请注意,在这种情况下需要两个 INSERT 语句。

因此,Department 实体类的脚手架 Insert 存储过程包含两个 SELECT 语句,因为这样一来,SQL 生成可扩展到多个 INSERT 语句的情况生成。虽然输出不适用于只有一个 INSERT 语句的情况,但可以手动编辑生成的存储过程主体,以便只有一个 SELECT声明。

关于c# - CUD : What is the purpose of the two SELECT statements in a scaffolded Insert stored procedure? 的存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32014909/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com