Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CUD存储过程:支架式Insert存储过程中两个SELECT语句的用途是什么?_C#_Sql Server_Stored Procedures_Entity Framework 6_Entity Framework Migrations - Fatal编程技术网

C# CUD存储过程:支架式Insert存储过程中两个SELECT语句的用途是什么?

C# CUD存储过程:支架式Insert存储过程中两个SELECT语句的用途是什么?,c#,sql-server,stored-procedures,entity-framework-6,entity-framework-migrations,C#,Sql Server,Stored Procedures,Entity Framework 6,Entity Framework Migrations,通过Tom Dykstra的教程,介绍了如何设置EF6以使用CUD的存储过程 当通过package manager控制台添加DepartmentSP迁移时,将自动生成以下CreateStoredProcedure()调用以创建Department\u Insert存储过程: CreateStoredProcedure( "dbo.Department_Insert", p => new { Name = p.String(maxLen

通过Tom Dykstra的教程,介绍了如何设置EF6以使用CUD的存储过程

当通过package manager控制台添加
DepartmentSP
迁移时,将自动生成以下CreateStoredProcedure()调用以创建Department\u 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()"
);
。。这看起来很好,但我可能遗漏了什么


我读过书,也读过书。另外,我查看了EF6 git提交历史记录,发现这是在迁移中启用存储过程支架的第一部分。

不幸的是,实体框架经常生成看起来不必要复杂的代码。它似乎更喜欢将查询分解成更多、更小的语句,而不是将其全部处理在一个语句中。同时,请记住,它的代码并非真正设计为“人类可读”,而手写的t-sql通常是这样。这个问题在这个问题上有一些很好的答案:
我想我已经明白了

生成插入存储过程主体的代码可以在中的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("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; }
}
ExtraSpecialLorder实体的脚手架插入存储过程为:

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
语句