Skip to content

Commit

Permalink
Fix #3704 - Explicit separation of command construction and execution
Browse files Browse the repository at this point in the history
Fix #3115 - Support passing DbParameter instances to ExecuteSqlCommand
and FromSql
Fix #2315 - Improve FromSql command caching
  • Loading branch information
mikary committed Mar 11, 2016
1 parent b2405e3 commit d89beca
Show file tree
Hide file tree
Showing 38 changed files with 1,488 additions and 621 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -295,15 +295,18 @@
<Compile Include="RelationalQueryableExtensions.cs" />
<Compile Include="RelationalReferenceCollectionBuilderExtensions.cs" />
<Compile Include="RelationalReferenceReferenceBuilderExtensions.cs" />
<Compile Include="Storage\CompositeRelationalParameter.cs" />
<Compile Include="Storage\DbContextTransactionExtensions.cs" />
<Compile Include="Storage\Internal\CompositeRelationalParameter.cs" />
<Compile Include="Storage\Internal\DynamicRelationalParameter.cs" />
<Compile Include="Storage\Internal\RawSqlCommandBuilder.cs" />
<Compile Include="Storage\Internal\RelationalCommand.cs" />
<Compile Include="Storage\Internal\RelationalCommandBuilder.cs" />
<Compile Include="Storage\Internal\RelationalCommandBuilderFactory.cs" />
<Compile Include="Storage\Internal\RelationalCommandExtensions.cs" />
<Compile Include="Storage\Internal\RelationalParameterBuilder.cs" />
<Compile Include="Storage\Internal\RemappingUntypedRelationalValueBufferFactory.cs" />
<Compile Include="Storage\Internal\TypedRelationalValueBufferFactory.cs" />
<Compile Include="Storage\Internal\TypeMappedRelationalParameter.cs" />
<Compile Include="Storage\Internal\UntypedRelationalValueBufferFactory.cs" />
<Compile Include="Storage\IParameterNameGeneratorFactory.cs" />
<Compile Include="Storage\IRawSqlCommandBuilder.cs" />
Expand All @@ -314,20 +317,21 @@
<Compile Include="Storage\IRelationalDatabaseCreator.cs" />
<Compile Include="Storage\IRelationalDatabaseProviderServices.cs" />
<Compile Include="Storage\IRelationalParameter.cs" />
<Compile Include="Storage\IRelationalParameterBuilder.cs" />
<Compile Include="Storage\IRelationalTransactionManager.cs" />
<Compile Include="Storage\IRelationalTypeMapper.cs" />
<Compile Include="Storage\IRelationalValueBufferFactory.cs" />
<Compile Include="Storage\IRelationalValueBufferFactoryFactory.cs" />
<Compile Include="Storage\ISqlGenerationHelper.cs" />
<Compile Include="Storage\ParameterNameGenerator.cs" />
<Compile Include="Storage\ParameterNameGeneratorFactory.cs" />
<Compile Include="Storage\RawSqlCommand.cs" />
<Compile Include="Storage\RelationalCommandBuilderExtensions.cs" />
<Compile Include="Storage\RelationalConnection.cs" />
<Compile Include="Storage\RelationalDatabase.cs" />
<Compile Include="Storage\RelationalDatabaseCreator.cs" />
<Compile Include="Storage\RelationalDatabaseProviderServices.cs" />
<Compile Include="Storage\RelationalDataReader.cs" />
<Compile Include="Storage\RelationalParameter.cs" />
<Compile Include="Storage\RelationalSizedTypeMapping.cs" />
<Compile Include="Storage\RelationalSqlGenerationHelper.cs" />
<Compile Include="Storage\RelationalTransaction.cs" />
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@
<data name="ClientEvalWarning" xml:space="preserve">
<value>The LINQ expression '{expression}' could not be translated and will be evaluated locally.</value>
</data>
<data name="MissingParameterValue" xml:space="preserve">
<value>No value provided for required parameter '{parameter}'.</value>
</data>
<data name="ParameterNotObjectArray" xml:space="preserve">
<value>Cannot use the value provided for parameter '{parameter}' because it isn't assignable to type object[].</value>
</data>
<data name="RelationalLoggerExecutedCommand" xml:space="preserve">
<value>Executed DbCommand ({elapsed}ms) [Parameters=[{parameters}], CommandType='{commandType}', CommandTimeout='{commandTimeout}']{newLine}{commandText}</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ await _queryingEnumerable._relationalQueryContext
_dataReader
= await relationalCommand.ExecuteReaderAsync(
_queryingEnumerable._relationalQueryContext.Connection,
_queryingEnumerable._relationalQueryContext.ParameterValues,
manageConnection: false,
parameterValues: _queryingEnumerable._relationalQueryContext.ParameterValues,
cancellationToken: cancellationToken);

_dbDataReader = _dataReader.DbDataReader;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ var relationalCommand
_dataReader
= relationalCommand.ExecuteReader(
_queryingEnumerable._relationalQueryContext.Connection,
manageConnection: false,
parameterValues: _queryingEnumerable._relationalQueryContext.ParameterValues);
_queryingEnumerable._relationalQueryContext.ParameterValues,
manageConnection: false);

_dbDataReader = _dataReader.DbDataReader;
_queryingEnumerable._shaperCommandContext.NotifyReaderCreated(_dbDataReader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,25 @@ public override bool Equals(object obj)
return false;
}

if (value is IEnumerable
&& value.GetType() != typeof(string)
&& value.GetType() != typeof(byte[]))
if (value is IEnumerable)
{
// TODO: This doesn't always need to be deep.
// We could add a LINQ operator parameter attribute to tell us.
return StructuralComparisons
.StructuralEqualityComparer.Equals(value, otherValue);
var type = value.GetType();

if (type == typeof(object[]))
{
// Only compare lengths for FromSql parameters
return ((object[])value).Length == (otherValue as object[])?.Length;
}

if (type != typeof(string)
&& type != typeof(byte[]))
{
// Comparision for contains parameters
// TODO: This doesn't always need to be deep.
// We could add a LINQ operator parameter attribute to tell us.
return StructuralComparisons
.StructuralEqualityComparer.Equals(value, otherValue);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,28 +340,21 @@ protected virtual void GenerateFromSql(

substitutions = new string[argumentValues.Length];

for (var i = 0; i < argumentValues.Length; i++)
{
var parameterName = _parameterNameGenerator.GenerateNext();

substitutions[i] = SqlGenerator.GenerateParameterName(parameterName);

var value = argumentValues[i];
_relationalCommandBuilder.AddCompositeParameter(
parameterExpression.Name,
builder =>
{
for (var i = 0; i < argumentValues.Length; i++)
{
var parameterName = _parameterNameGenerator.GenerateNext();
relationalParameters[i]
= _relationalCommandBuilder
.CreateParameter(
substitutions[i],
value,
t => t.GetMappingForValue(value),
value?.GetType().IsNullableType(),
parameterName);
}
substitutions[i] = SqlGenerator.GenerateParameterName(parameterName);
_relationalCommandBuilder.AddParameter(
new CompositeRelationalParameter(
parameterExpression.Name,
relationalParameters));
builder.AddParameter(
parameterName,
substitutions[i]);
}
});
}

break;
Expand Down Expand Up @@ -405,14 +398,13 @@ protected virtual void GenerateFromSql(
{
var parameter = (ParameterExpression)expression;

object value;
if (_parametersValues.TryGetValue(parameter.Name, out value))
if (_parametersValues.ContainsKey(parameter.Name))
{
var parameterName = _sqlGenerationHelper.GenerateParameterName(parameter.Name);

substitutions[i] = parameterName;
substitutions[i] = _sqlGenerationHelper.GenerateParameterName(parameter.Name);

_relationalCommandBuilder.AddParameter(parameterName, value, parameter.Name);
_relationalCommandBuilder.AddParameter(
parameter.Name,
substitutions[i]);
}

break;
Expand Down Expand Up @@ -1125,14 +1117,18 @@ protected override Expression VisitParameter(ParameterExpression expression)
{
Check.NotNull(expression, nameof(expression));

object value;
if (_parametersValues.TryGetValue(expression.Name, out value))
{
var name = _sqlGenerationHelper.GenerateParameterName(expression.Name);
var name = _sqlGenerationHelper.GenerateParameterName(expression.Name);

_relationalCommandBuilder.AppendParameter(name, value, expression.Type, expression.Name);
if (_relationalCommandBuilder.ParameterBuilder.Parameters.All(p => p.InvariantName != expression.Name))
{
_relationalCommandBuilder.AddParameter(
expression.Name,
name,
expression.Type);
}

_relationalCommandBuilder.Append(name);

return expression;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,15 @@ public static int ExecuteSqlCommand(

using (concurrencyDetector.EnterCriticalSection())
{
return databaseFacade
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters)
.ExecuteNonQuery(GetRelationalConnection(databaseFacade));
.Build(sql, parameters);

return rawSqlCommand
.RelationalCommand
.ExecuteNonQuery(
GetRelationalConnection(databaseFacade),
parameterValues: rawSqlCommand.ParameterValues);
}
}

Expand All @@ -68,10 +73,16 @@ public static async Task<int> ExecuteSqlCommandAsync(

using (concurrencyDetector.EnterCriticalSection())
{
return await databaseFacade
var rawSqlCommand = databaseFacade
.GetService<IRawSqlCommandBuilder>()
.Build(sql, parameters)
.ExecuteNonQueryAsync(GetRelationalConnection(databaseFacade), cancellationToken: cancellationToken);
.Build(sql, parameters);

return await rawSqlCommand
.RelationalCommand
.ExecuteNonQueryAsync(
GetRelationalConnection(databaseFacade),
parameterValues: rawSqlCommand.ParameterValues,
cancellationToken: cancellationToken);
}
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ namespace Microsoft.EntityFrameworkCore.Storage
{
public interface IRawSqlCommandBuilder
{
IRelationalCommand Build(
IRelationalCommand Build([NotNull] string sql);

RawSqlCommand Build(
[NotNull] string sql,
[CanBeNull] IReadOnlyList<object> parameters = null);
[NotNull] IReadOnlyList<object> parameters);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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.Collections.Generic;
Expand All @@ -16,31 +16,35 @@ public interface IRelationalCommand

int ExecuteNonQuery(
[NotNull] IRelationalConnection connection,
[CanBeNull] IReadOnlyDictionary<string, object> parameterValues = null,
bool manageConnection = true);

Task<int> ExecuteNonQueryAsync(
[NotNull] IRelationalConnection connection,
[CanBeNull] IReadOnlyDictionary<string, object> parameterValues = null,
bool manageConnection = true,
CancellationToken cancellationToken = default(CancellationToken));

object ExecuteScalar(
[NotNull] IRelationalConnection connection,
[CanBeNull] IReadOnlyDictionary<string, object> parameterValues = null,
bool manageConnection = true);

Task<object> ExecuteScalarAsync(
[NotNull] IRelationalConnection connection,
[CanBeNull] IReadOnlyDictionary<string, object> parameterValues = null,
bool manageConnection = true,
CancellationToken cancellationToken = default(CancellationToken));

RelationalDataReader ExecuteReader(
[NotNull] IRelationalConnection connection,
bool manageConnection = true,
[CanBeNull] IReadOnlyDictionary<string, object> parameterValues = null);
[CanBeNull] IReadOnlyDictionary<string, object> parameterValues = null,
bool manageConnection = true);

Task<RelationalDataReader> ExecuteReaderAsync(
[NotNull] IRelationalConnection connection,
bool manageConnection = true,
[CanBeNull] IReadOnlyDictionary<string, object> parameterValues = null,
bool manageConnection = true,
CancellationToken cancellationToken = default(CancellationToken));
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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 JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;

namespace Microsoft.EntityFrameworkCore.Storage
{
public interface IRelationalCommandBuilder : IInfrastructure<IndentedStringBuilder>
{
void AddParameter([NotNull] IRelationalParameter relationalParameter);

IRelationalParameter CreateParameter(
[NotNull] string name,
[CanBeNull] object value,
[NotNull] Func<IRelationalTypeMapper, RelationalTypeMapping> mapType,
bool? nullable,
[CanBeNull] string invariantName);
IRelationalParameterBuilder ParameterBuilder { get; }

IRelationalCommand Build();
}
Expand Down
Loading

0 comments on commit d89beca

Please sign in to comment.