Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw detailed exception message in buffered data reader #22233

Merged
1 commit merged into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

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

3 changes: 3 additions & 0 deletions src/EFCore.Relational/Properties/RelationalStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@
<data name="FunctionOverrideMismatch" xml:space="preserve">
<value>The property '{propertySpecification}' has specific configuration for the function '{function}', however it isn't mapped to a column on that function return. Remove the specific configuration or map an entity type that contains this property to '{function}'.</value>
</data>
<data name="GetXMethodOnNullData" xml:space="preserve">
<value>Data is Null. This method or property cannot be called on Null values.</value>
</data>
<data name="IncompatibleTableCommentMismatch" xml:space="preserve">
<value>Cannot use table '{table}' for entity type '{entityType}' since it is being used for entity type '{otherEntityType}' and the comment '{comment}' does not match the comment '{otherComment}'.</value>
</data>
Expand Down
467 changes: 384 additions & 83 deletions src/EFCore.Relational/Query/Internal/BufferedDataReader.cs

Large diffs are not rendered by default.

64 changes: 36 additions & 28 deletions src/EFCore.Relational/Query/Internal/FromSqlQueryingEnumerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class FromSqlQueryingEnumerable<T> : IEnumerable<T>, IAsyncEnumerable<T>,
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
private readonly bool _standAloneStateManager;
private readonly bool _detailedErrorsEnabled;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -43,7 +44,8 @@ public FromSqlQueryingEnumerable(
[NotNull] IReadOnlyList<string> columnNames,
[NotNull] Func<QueryContext, DbDataReader, int[], T> shaper,
[NotNull] Type contextType,
bool standAloneStateManager)
bool standAloneStateManager,
bool detailedErrorsEnabled)
{
_relationalQueryContext = relationalQueryContext;
_relationalCommandCache = relationalCommandCache;
Expand All @@ -52,6 +54,7 @@ public FromSqlQueryingEnumerable(
_contextType = contextType;
_queryLogger = relationalQueryContext.QueryLogger;
_standAloneStateManager = standAloneStateManager;
_detailedErrorsEnabled = detailedErrorsEnabled;
}

/// <summary>
Expand All @@ -61,7 +64,11 @@ public FromSqlQueryingEnumerable(
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
=> new AsyncEnumerator(this, cancellationToken);
{
_relationalQueryContext.CancellationToken = cancellationToken;

return new AsyncEnumerator(this);
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -96,7 +103,8 @@ public virtual DbCommand CreateDbCommand()
_relationalQueryContext.ParameterValues,
null,
null,
null),
null,
_detailedErrorsEnabled),
Guid.Empty,
(DbCommandMethod)(-1));

Expand Down Expand Up @@ -144,6 +152,7 @@ private sealed class Enumerator : IEnumerator<T>
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
private readonly bool _standAloneStateManager;
private readonly bool _detailedErrorsEnabled;

private RelationalDataReader _dataReader;
private int[] _indexMap;
Expand All @@ -157,6 +166,7 @@ public Enumerator(FromSqlQueryingEnumerable<T> queryingEnumerable)
_contextType = queryingEnumerable._contextType;
_queryLogger = queryingEnumerable._queryLogger;
_standAloneStateManager = queryingEnumerable._standAloneStateManager;
_detailedErrorsEnabled = queryingEnumerable._detailedErrorsEnabled;
}

public T Current { get; private set; }
Expand Down Expand Up @@ -199,14 +209,14 @@ private bool InitializeReader(DbContext _, bool result)

var relationalCommand = _relationalCommandCache.GetRelationalCommand(_relationalQueryContext.ParameterValues);

_dataReader
= relationalCommand.ExecuteReader(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger));
_dataReader = relationalCommand.ExecuteReader(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger,
_detailedErrorsEnabled));

_indexMap = BuildIndexMap(_columnNames, _dataReader.DbDataReader);

Expand Down Expand Up @@ -234,14 +244,12 @@ private sealed class AsyncEnumerator : IAsyncEnumerator<T>
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
private readonly bool _standAloneStateManager;
private readonly CancellationToken _cancellationToken;
private readonly bool _detailedErrorsEnabled;

private RelationalDataReader _dataReader;
private int[] _indexMap;

public AsyncEnumerator(
FromSqlQueryingEnumerable<T> queryingEnumerable,
CancellationToken cancellationToken)
public AsyncEnumerator(FromSqlQueryingEnumerable<T> queryingEnumerable)
{
_relationalQueryContext = queryingEnumerable._relationalQueryContext;
_relationalCommandCache = queryingEnumerable._relationalCommandCache;
Expand All @@ -250,7 +258,7 @@ public AsyncEnumerator(
_contextType = queryingEnumerable._contextType;
_queryLogger = queryingEnumerable._queryLogger;
_standAloneStateManager = queryingEnumerable._standAloneStateManager;
_cancellationToken = cancellationToken;
_detailedErrorsEnabled = queryingEnumerable._detailedErrorsEnabled;
}

public T Current { get; private set; }
Expand All @@ -264,10 +272,10 @@ public async ValueTask<bool> MoveNextAsync()
if (_dataReader == null)
{
await _relationalQueryContext.ExecutionStrategyFactory.Create()
.ExecuteAsync(true, InitializeReaderAsync, null, _cancellationToken).ConfigureAwait(false);
.ExecuteAsync(true, InitializeReaderAsync, null, _relationalQueryContext.CancellationToken).ConfigureAwait(false);
}

var hasNext = await _dataReader.ReadAsync(_cancellationToken).ConfigureAwait(false);
var hasNext = await _dataReader.ReadAsync(_relationalQueryContext.CancellationToken).ConfigureAwait(false);

Current = hasNext
? _shaper(_relationalQueryContext, _dataReader.DbDataReader, _indexMap)
Expand All @@ -290,16 +298,16 @@ private async Task<bool> InitializeReaderAsync(DbContext _, bool result, Cancell

var relationalCommand = _relationalCommandCache.GetRelationalCommand(_relationalQueryContext.ParameterValues);

_dataReader
= await relationalCommand.ExecuteReaderAsync(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger),
cancellationToken)
.ConfigureAwait(false);
_dataReader = await relationalCommand.ExecuteReaderAsync(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger,
_detailedErrorsEnabled),
cancellationToken)
.ConfigureAwait(false);

_indexMap = BuildIndexMap(_columnNames, _dataReader.DbDataReader);

Expand Down
64 changes: 36 additions & 28 deletions src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class SingleQueryingEnumerable<T> : IEnumerable<T>, IAsyncEnumerable<T>,
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
private readonly bool _standAloneStateManager;
private readonly bool _detailedErrorsEnabled;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -40,14 +41,16 @@ public SingleQueryingEnumerable(
[NotNull] RelationalCommandCache relationalCommandCache,
[NotNull] Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, T> shaper,
[NotNull] Type contextType,
bool standAloneStateManager)
bool standAloneStateManager,
bool detailedErrorsEnabled)
{
_relationalQueryContext = relationalQueryContext;
_relationalCommandCache = relationalCommandCache;
_shaper = shaper;
_contextType = contextType;
_queryLogger = relationalQueryContext.QueryLogger;
_standAloneStateManager = standAloneStateManager;
_detailedErrorsEnabled = detailedErrorsEnabled;
}

/// <summary>
Expand All @@ -57,7 +60,11 @@ public SingleQueryingEnumerable(
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
=> new AsyncEnumerator(this, cancellationToken);
{
_relationalQueryContext.CancellationToken = cancellationToken;

return new AsyncEnumerator(this);
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -113,6 +120,7 @@ private sealed class Enumerator : IEnumerator<T>
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
private readonly bool _standAloneStateManager;
private readonly bool _detailedErrorsEnabled;

private RelationalDataReader _dataReader;
private SingleQueryResultCoordinator _resultCoordinator;
Expand All @@ -125,6 +133,7 @@ public Enumerator(SingleQueryingEnumerable<T> queryingEnumerable)
_contextType = queryingEnumerable._contextType;
_queryLogger = queryingEnumerable._queryLogger;
_standAloneStateManager = queryingEnumerable._standAloneStateManager;
_detailedErrorsEnabled = queryingEnumerable._detailedErrorsEnabled;
}

public T Current { get; private set; }
Expand Down Expand Up @@ -194,14 +203,14 @@ private bool InitializeReader(DbContext _, bool result)

var relationalCommand = _relationalCommandCache.GetRelationalCommand(_relationalQueryContext.ParameterValues);

_dataReader
= relationalCommand.ExecuteReader(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger));
_dataReader = relationalCommand.ExecuteReader(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger,
_detailedErrorsEnabled));

_resultCoordinator = new SingleQueryResultCoordinator();

Expand All @@ -228,22 +237,20 @@ private sealed class AsyncEnumerator : IAsyncEnumerator<T>
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
private readonly bool _standAloneStateManager;
private readonly CancellationToken _cancellationToken;
private readonly bool _detailedErrorsEnabled;

private RelationalDataReader _dataReader;
private SingleQueryResultCoordinator _resultCoordinator;

public AsyncEnumerator(
SingleQueryingEnumerable<T> queryingEnumerable,
CancellationToken cancellationToken)
public AsyncEnumerator(SingleQueryingEnumerable<T> queryingEnumerable)
{
_relationalQueryContext = queryingEnumerable._relationalQueryContext;
_relationalCommandCache = queryingEnumerable._relationalCommandCache;
_shaper = queryingEnumerable._shaper;
_contextType = queryingEnumerable._contextType;
_queryLogger = queryingEnumerable._queryLogger;
_standAloneStateManager = queryingEnumerable._standAloneStateManager;
_cancellationToken = cancellationToken;
_detailedErrorsEnabled = queryingEnumerable._detailedErrorsEnabled;
}

public T Current { get; private set; }
Expand All @@ -257,11 +264,12 @@ public async ValueTask<bool> MoveNextAsync()
if (_dataReader == null)
{
await _relationalQueryContext.ExecutionStrategyFactory.Create()
.ExecuteAsync(true, InitializeReaderAsync, null, _cancellationToken)
.ExecuteAsync(true, InitializeReaderAsync, null, _relationalQueryContext.CancellationToken)
.ConfigureAwait(false);
}

var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(_cancellationToken).ConfigureAwait(false);
var hasNext = _resultCoordinator.HasNext
?? await _dataReader.ReadAsync(_relationalQueryContext.CancellationToken).ConfigureAwait(false);
Current = default;

if (hasNext)
Expand All @@ -280,7 +288,7 @@ await _relationalQueryContext.ExecutionStrategyFactory.Create()
break;
}

if (!await _dataReader.ReadAsync(_cancellationToken).ConfigureAwait(false))
if (!await _dataReader.ReadAsync(_relationalQueryContext.CancellationToken).ConfigureAwait(false))
{
_resultCoordinator.HasNext = false;
// Enumeration has ended, materialize last element
Expand Down Expand Up @@ -311,16 +319,16 @@ private async Task<bool> InitializeReaderAsync(DbContext _, bool result, Cancell

var relationalCommand = _relationalCommandCache.GetRelationalCommand(_relationalQueryContext.ParameterValues);

_dataReader
= await relationalCommand.ExecuteReaderAsync(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger),
cancellationToken)
.ConfigureAwait(false);
_dataReader = await relationalCommand.ExecuteReaderAsync(
new RelationalCommandParameterObject(
_relationalQueryContext.Connection,
_relationalQueryContext.ParameterValues,
_relationalCommandCache.ReaderColumns,
_relationalQueryContext.Context,
_relationalQueryContext.CommandLogger,
_detailedErrorsEnabled),
cancellationToken)
.ConfigureAwait(false);

_resultCoordinator = new SingleQueryResultCoordinator();

Expand Down
Loading