From 7198a9836d3d12bfc89a76fa027475a50534ddea Mon Sep 17 00:00:00 2001 From: Smit Patel Date: Thu, 10 Sep 2020 13:48:04 -0700 Subject: [PATCH] Clone DbParameter when adding to command if ICloneable Resolves #22483 --- .../Internal/RawRelationalParameter.cs | 6 +++++ .../Query/FromSqlQueryTestBase.cs | 16 +++++++++++++ .../Query/FromSqlQuerySqlServerTest.cs | 23 +++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/src/EFCore.Relational/Storage/Internal/RawRelationalParameter.cs b/src/EFCore.Relational/Storage/Internal/RawRelationalParameter.cs index 5e0cb1a2f0e..c9d7e8dd825 100644 --- a/src/EFCore.Relational/Storage/Internal/RawRelationalParameter.cs +++ b/src/EFCore.Relational/Storage/Internal/RawRelationalParameter.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Data.Common; using JetBrains.Annotations; @@ -62,6 +63,11 @@ public override void AddDbParameter(DbCommand command, IReadOnlyDictionary public override void AddDbParameter(DbCommand command, object value) { + if (value is ICloneable cloneable) + { + value = cloneable.Clone(); + } + command.Parameters.Add(value); } } diff --git a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs index df0f2e7b1e2..875094aee12 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs @@ -987,6 +987,22 @@ public virtual void Line_endings_after_Select() Assert.NotNull(actual); } + [ConditionalFact] + public virtual void FromSql_with_db_parameter_in_split_query() + { + using var context = CreateContext(); + + var actual = context.Set() + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), + CreateDbParameter("customerID", "ALFKI")) + .Include(e => e.Orders) + .AsSplitQuery() + .ToArray(); + + var customer = Assert.Single(actual); + Assert.Equal(6, customer.Orders.Count); + } + protected string NormalizeDelimitersInRawString(string sql) => Fixture.TestStore.NormalizeDelimitersInRawString(sql); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs index c550dc1daf6..b34f2f6fcb9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs @@ -799,6 +799,29 @@ public override void Line_endings_after_Select() WHERE [c].[City] = N'Seattle'"); } + public override void FromSql_with_db_parameter_in_split_query() + { + base.FromSql_with_db_parameter_in_split_query(); + + AssertSql( + @"customerID='ALFKI' (Nullable = false) (Size = 5) + +SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM ( + SELECT * FROM ""Customers"" WHERE ""CustomerID"" = @customerID +) AS [c] +ORDER BY [c].[CustomerID]", + // + @"customerID='ALFKI' (Nullable = false) (Size = 5) + +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[CustomerID] +FROM ( + SELECT * FROM ""Customers"" WHERE ""CustomerID"" = @customerID +) AS [c] +INNER JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +ORDER BY [c].[CustomerID]"); + } + protected override DbParameter CreateDbParameter(string name, object value) => new SqlParameter { ParameterName = name, Value = value };