From f3e95a9db4716c08c14a030029d06882d8571d52 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 11 Aug 2022 14:21:33 +0200 Subject: [PATCH] Add inheritance tests --- .../StoredProcedureUpdateContext.cs | 17 ++ .../StoredProcedureUpdateModel/TpcChild.cs | 9 + .../StoredProcedureUpdateModel/TpcParent.cs | 10 ++ .../StoredProcedureUpdateModel/TphChild.cs | 9 + .../StoredProcedureUpdateModel/TphParent.cs | 10 ++ .../StoredProcedureUpdateModel/TptChild.cs | 9 + .../TptMixedChild.cs | 9 + .../TptMixedParent.cs | 10 ++ .../StoredProcedureUpdateModel/TptParent.cs | 10 ++ .../StoredProcedureUpdateFixtureBase.cs | 65 ++++++- .../Update/StoredProcedureUpdateTestBase.cs | 85 ++++++++- .../StoredProcedureUpdateSqlServerTest.cs | 167 +++++++++++++++--- 12 files changed, 382 insertions(+), 28 deletions(-) create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcChild.cs create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcParent.cs create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphChild.cs create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphParent.cs create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptChild.cs create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedChild.cs create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedParent.cs create mode 100644 test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptParent.cs diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/StoredProcedureUpdateContext.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/StoredProcedureUpdateContext.cs index 865fa2221fa..2ae147a0993 100644 --- a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/StoredProcedureUpdateContext.cs +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/StoredProcedureUpdateContext.cs @@ -49,6 +49,15 @@ public DbSet WithOriginalAndCurrentValueOnNonConcurrencyToken public DbSet WithInputOutputParameterOnNonConcurrencyToken => Set(nameof(WithInputOutputParameterOnNonConcurrencyToken)); + public DbSet TphParent { get; set; } + public DbSet TphChild { get; set; } + public DbSet TptParent { get; set; } + public DbSet TptChild { get; set; } + public DbSet TptMixedParent { get; set; } + public DbSet TptMixedChild { get; set; } + public DbSet TpcParent { get; set; } + public DbSet TpcChild { get; set; } + public static void Clean(StoredProcedureUpdateContext context) { context.WithOutputParameter.RemoveRange(context.WithOutputParameter); @@ -64,6 +73,14 @@ public static void Clean(StoredProcedureUpdateContext context) context.WithUserManagedConcurrencyToken.RemoveRange(context.WithUserManagedConcurrencyToken); context.WithOriginalAndCurrentValueOnNonConcurrencyToken.RemoveRange(context.WithOriginalAndCurrentValueOnNonConcurrencyToken); context.WithInputOutputParameterOnNonConcurrencyToken.RemoveRange(context.WithInputOutputParameterOnNonConcurrencyToken); + context.TphParent.RemoveRange(context.TphParent); + context.TphChild.RemoveRange(context.TphChild); + context.TptParent.RemoveRange(context.TptParent); + context.TptChild.RemoveRange(context.TptChild); + context.TptMixedParent.RemoveRange(context.TptMixedParent); + context.TptMixedChild.RemoveRange(context.TptMixedChild); + context.TpcParent.RemoveRange(context.TpcParent); + context.TpcChild.RemoveRange(context.TpcChild); context.SaveChanges(); } diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcChild.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcChild.cs new file mode 100644 index 00000000000..dc68342567f --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcChild.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TpcChild : TpcParent +{ + public int ChildProperty { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcParent.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcParent.cs new file mode 100644 index 00000000000..801a45b95d2 --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TpcParent.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TpcParent +{ + public int Id { get; set; } + public string Name { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphChild.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphChild.cs new file mode 100644 index 00000000000..acf252e5ede --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphChild.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TphChild : TphParent +{ + public int ChildProperty { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphParent.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphParent.cs new file mode 100644 index 00000000000..b8583fe1525 --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TphParent.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TphParent +{ + public int Id { get; set; } + public string Name { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptChild.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptChild.cs new file mode 100644 index 00000000000..3d3d2e8266c --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptChild.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TptChild : TptParent +{ + public int ChildProperty { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedChild.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedChild.cs new file mode 100644 index 00000000000..b37fc9fc324 --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedChild.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TptMixedChild : TptMixedParent +{ + public int ChildProperty { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedParent.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedParent.cs new file mode 100644 index 00000000000..209f056bee1 --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptMixedParent.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TptMixedParent +{ + public int Id { get; set; } + public string Name { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptParent.cs b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptParent.cs new file mode 100644 index 00000000000..fd5646fe143 --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/TestModels/StoredProcedureUpdateModel/TptParent.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + +public class TptParent +{ + public int Id { get; set; } + public string Name { get; set; } +} diff --git a/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateFixtureBase.cs b/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateFixtureBase.cs index 7fe67bd0e6a..eeb98b5c865 100644 --- a/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateFixtureBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateFixtureBase.cs @@ -158,13 +158,76 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(w => w.AdditionalProperty2).HasComputedColumnSql("9"); b.UpdateUsingStoredProcedure( - "WithOutputParameterAndResultColumnAndResultValue_Update", spb => spb + nameof(StoredProcedureUpdateContext.WithOutputParameterAndResultColumnAndResultValue) + "_Update", + spb => spb .HasParameter(w => w.Id) .HasParameter(w => w.Name) .HasParameter(w => w.AdditionalProperty1, pb => pb.IsOutput()) .HasResultColumn(w => w.AdditionalProperty2) .HasRowsAffectedReturnValue()); }); + + modelBuilder.Entity( + b => + { + b.ToTable("Tph"); + + b.InsertUsingStoredProcedure( + "Tph_Insert", + spb => spb + .HasParameter(w => w.Id, pb => pb.IsOutput()) + .HasParameter("Discriminator") + .HasParameter(w => w.Name) + .HasParameter(nameof(TphChild.ChildProperty))); + }); + + modelBuilder.Entity().ToTable("Tph"); + + modelBuilder.Entity( + b => + { + b.UseTptMappingStrategy(); + + b.InsertUsingStoredProcedure( + "TptParent_Insert", + spb => spb + .HasParameter(w => w.Id, pb => pb.IsOutput()) + .HasParameter(w => w.Name)); + }); + + // TODO: The following fails validation: + // The entity type 'TptChild' is mapped to the stored procedure 'TptChild_Insert', however the store-generated properties {'Id'} are not mapped to any output parameter or result column. + modelBuilder.Entity() + .InsertUsingStoredProcedure( + "TptChild_Insert", + spb => spb + .HasParameter(w => w.Id) + .HasParameter(w => w.ChildProperty)); + + modelBuilder.Entity( + b => + { + b.UseTptMappingStrategy(); + + b.InsertUsingStoredProcedure( + "TptMixedParent_Insert", + spb => spb + .HasParameter(w => w.Id, pb => pb.IsOutput()) + .HasParameter(w => w.Name)); + }); + + // No sproc mapping for TptMixedChild, use regular SQL + + modelBuilder.Entity().UseTpcMappingStrategy(); + + modelBuilder.Entity() + .UseTpcMappingStrategy() + .InsertUsingStoredProcedure( + "TpcChild_Insert", + spb => spb + .HasParameter(w => w.Id, pb => pb.IsOutput()) + .HasParameter(w => w.Name) + .HasParameter(w => w.ChildProperty)); } /// diff --git a/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateTestBase.cs b/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateTestBase.cs index 5a895d1354e..dfa484350cf 100644 --- a/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Update/StoredProcedureUpdateTestBase.cs @@ -466,7 +466,90 @@ public virtual async Task Update_with_output_parameter_and_result_column_and_ret } } - // TODO: Hierarchy tests (TPC/TPT/TPH), mixed sproc+non-sproc in the same hierarchy + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Tph(bool async) + { + await using var context = CreateContext(); + + var entity1 = new TphChild { Name = "Child", ChildProperty = 8 }; + context.TphChild.Add(entity1); + await SaveChanges(context, async); + + context.ChangeTracker.Clear(); + + using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents()) + { + var entity2 = context.TphChild.Single(b => b.Id == entity1.Id); + + Assert.Equal("Child", entity2.Name); + Assert.Equal(8, entity2.ChildProperty); + } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Tpt(bool async) + { + await using var context = CreateContext(); + + var entity1 = new TptChild { Name = "Child", ChildProperty = 8 }; + context.TptChild.Add(entity1); + await SaveChanges(context, async); + + context.ChangeTracker.Clear(); + + using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents()) + { + var entity2 = context.TptChild.Single(b => b.Id == entity1.Id); + + Assert.Equal("Child", entity2.Name); + Assert.Equal(8, entity2.ChildProperty); + } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Tpt_mixed_sproc_and_non_sproc(bool async) + { + await using var context = CreateContext(); + + var entity1 = new TptMixedChild { Name = "Child", ChildProperty = 8 }; + context.TptMixedChild.Add(entity1); + await SaveChanges(context, async); + + context.ChangeTracker.Clear(); + + using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents()) + { + var entity2 = context.TptMixedChild.Single(b => b.Id == entity1.Id); + + Assert.Equal("Child", entity2.Name); + Assert.Equal(8, entity2.ChildProperty); + } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Tpc(bool async) + { + await using var context = CreateContext(); + + var entity1 = new TpcChild { Name = "Child", ChildProperty = 8 }; + context.TpcChild.Add(entity1); + await SaveChanges(context, async); + + context.ChangeTracker.Clear(); + + using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents()) + { + var entity2 = context.TpcChild.Single(b => b.Id == entity1.Id); + + Assert.Equal("Child", entity2.Name); + Assert.Equal(8, entity2.ChildProperty); + } + } + private async Task SaveChanges(StoredProcedureUpdateContext context, bool async) { if (async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/StoredProcedureUpdateSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Update/StoredProcedureUpdateSqlServerTest.cs index b395f63b6b4..09f56e15bf4 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Update/StoredProcedureUpdateSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/StoredProcedureUpdateSqlServerTest.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.EntityFrameworkCore.TestModels.StoredProcedureUpdateModel; + namespace Microsoft.EntityFrameworkCore.Update; #nullable enable @@ -12,7 +14,7 @@ public StoredProcedureUpdateSqlServerTest(StoredProcedureUpdateSqlServerFixture : base(fixture) { Fixture.TestSqlLoggerFactory.Clear(); - // Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } public override async Task Insert_with_output_parameter(bool async) @@ -260,6 +262,72 @@ public override async Task Original_and_current_value_on_non_concurrency_token(b EXEC [WithOriginalAndCurrentValueOnNonConcurrencyToken_Update] @p0, @p1, @p2;"); } + public override async Task Tph(bool async) + { + await base.Tph(async); + + AssertSql( + @"@p0='1' (Direction = Output) +@p1='TphChild' (Nullable = false) (Size = 4000) +@p2='Child' (Size = 4000) +@p3='8' (Nullable = true) + +SET NOCOUNT ON; +EXEC [Tph_Insert] @p0 OUTPUT, @p1, @p2, @p3;"); + } + + public override async Task Tpt(bool async) + { + await base.Tpt(async); + + AssertSql( + @"@p0='1' (Direction = Output) +@p1='TphChild' (Nullable = false) (Size = 4000) +@p2='Child' (Size = 4000) +@p3='8' (Nullable = true) + +SET NOCOUNT ON; +EXEC [Tph_Insert] @p0 OUTPUT, @p1, @p2, @p3;"); + } + + public override async Task Tpt_mixed_sproc_and_non_sproc(bool async) + { + await base.Tpt_mixed_sproc_and_non_sproc(async); + + // TODO: The sproc doesn't get used below; InsertStoredProcedureMapping is null on the ITableMapping in CommandBatchPreparer.CreateModificationCommands + AssertSql( + @"@p0='Child' (Size = 4000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [TptMixedParent] ([Name]) +OUTPUT INSERTED.[Id] +VALUES (@p0);", + // + @"@p1='1' +@p2='8' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [TptMixedChild] ([Id], [ChildProperty]) +VALUES (@p1, @p2);"); + + throw new NotImplementedException(); + } + + public override async Task Tpc(bool async) + { + await base.Tpc(async); + + AssertSql( + @"@p0='1' (Direction = Output) +@p1='Child' (Size = 4000) +@p2='8' + +SET NOCOUNT ON; +EXEC [TpcChild_Insert] @p0 OUTPUT, @p1, @p2;"); + } + public override async Task Input_output_parameter_on_non_concurrency_token(bool async) { await base.Input_output_parameter_on_non_concurrency_token(async); @@ -276,8 +344,6 @@ public class StoredProcedureUpdateSqlServerFixture : StoredProcedureUpdateFixtur protected override ITestStoreFactory TestStoreFactory => StoredProcedureTestStoryFactory.Instance; - private string? _truncateCommand; - protected override void ConfigureStoreGeneratedConcurrencyToken(EntityTypeBuilder entityTypeBuilder, string propertyName) => entityTypeBuilder.Property(propertyName).IsRowVersion(); @@ -289,29 +355,37 @@ public override void Reseed() } protected override void Clean(DbContext context) - => context.Database.ExecuteSqlRaw(GetTruncateCommand()); - - private string GetTruncateCommand() - { - if (_truncateCommand is not null) - { - return _truncateCommand; - } - - var context = CreateContext(); - var builder = new StringBuilder(); - - var helper = context.GetService(); - var tables = context.Model.GetEntityTypes() - .SelectMany(e => e.GetTableMappings().Select(m => helper.DelimitIdentifier(m.Table.Name, m.Table.Schema))); - - foreach (var table in tables) - { - builder.AppendLine($"TRUNCATE TABLE {table};"); - } - - return _truncateCommand = builder.ToString(); - } + => context.Database.ExecuteSqlRaw(EmptyTablesCommand); + + private const string EmptyTablesCommand = @" +-- Regular tables without foreign keys +TRUNCATE TABLE [WithInputOutputParameterOnNonConcurrencyToken]; +TRUNCATE TABLE [WithOriginalAndCurrentValueOnNonConcurrencyToken]; +TRUNCATE TABLE [WithOutputParameter]; +TRUNCATE TABLE [WithOutputParameterAndResultColumn]; +TRUNCATE TABLE [WithOutputParameterAndResultColumnAndResultValue]; +TRUNCATE TABLE [WithResultColumn]; +TRUNCATE TABLE [WithRowsAffectedParameter]; +TRUNCATE TABLE [WithRowsAffectedResultColumn]; +TRUNCATE TABLE [WithRowsAffectedReturnValue]; +TRUNCATE TABLE [WithStoreGeneratedConcurrencyTokenAsInoutParameter]; +TRUNCATE TABLE [WithStoreGeneratedConcurrencyTokenAsTwoParameters]; +TRUNCATE TABLE [WithTwoOutputParameters]; +TRUNCATE TABLE [WithUserManagedConcurrencyToken]; +TRUNCATE TABLE [Tph]; +TRUNCATE TABLE [Tph]; +TRUNCATE TABLE [TpcChild]; +TRUNCATE TABLE [TpcParent]; + +ALTER SEQUENCE [TpcParentSequence] RESTART WITH 1 + +DELETE FROM [TptMixedChild]; +DELETE FROM [TptMixedParent]; +DBCC CHECKIDENT ('[TptMixedParent]', RESEED, 0); + +DELETE FROM [TptChild]; +DELETE FROM [TptParent]; +DBCC CHECKIDENT ('[TptParent]', RESEED, 0);"; class StoredProcedureTestStoryFactory : SqlServerTestStoreFactory { @@ -428,6 +502,47 @@ AS BEGIN UPDATE [WithOutputParameterAndResultColumnAndResultValue] SET [Name] = @Name, @AdditionalProperty1 = [AdditionalProperty1] WHERE [Id] = @Id; SELECT [AdditionalProperty2] FROM [WithOutputParameterAndResultColumnAndResultValue] WHERE [Id] = @Id RETURN @@ROWCOUNT; +END; + +GO + +CREATE PROCEDURE Tph_Insert(@Id int OUT, @Discriminator varchar(max), @Name varchar(max), @ChildProperty int) +AS BEGIN + INSERT INTO [Tph] ([Discriminator], [Name], [ChildProperty]) VALUES (@Discriminator, @Name, @ChildProperty); + SET @Id = SCOPE_IDENTITY(); +END; + +GO + +CREATE PROCEDURE TptParent_Insert(@Id int OUT, @Name varchar(max)) +AS BEGIN + INSERT INTO [TptParent] ([Name]) VALUES (@Name); + SET @Id = SCOPE_IDENTITY(); +END; + +GO + +CREATE PROCEDURE TptMixedParent_Insert(@Id int OUT, @Name varchar(max)) +AS BEGIN + INSERT INTO [TptMixedParent] ([Name]) VALUES (@Name); + SET @Id = SCOPE_IDENTITY(); +END; + +GO + +CREATE PROCEDURE TptChild_Insert(@Id int, @ChildProperty int) +AS BEGIN + INSERT INTO [TptChild] ([Id], [ChildProperty]) VALUES (@Id, @ChildProperty); + SET @Id = SCOPE_IDENTITY(); +END; + +GO + +CREATE PROCEDURE TpcChild_Insert(@Id int OUT, @Name varchar(max), @ChildProperty int) +AS BEGIN + DECLARE @Table table ([Id] int); + INSERT INTO [TpcChild] ([Name], [ChildProperty]) OUTPUT [Inserted].[Id] INTO @Table VALUES (@Name, @ChildProperty); + SELECT @Id = [Id] FROM @Table; END;"; } }