Skip to content

Commit

Permalink
Improve expression debugging
Browse files Browse the repository at this point in the history
* Add [DebuggerDisplay] to non-SqlExpressions too (OrderingExpression,
  ProjectionExpression).
* For SelectExpression, show the SQL in [DebuggerDisplay] and add a
  DebugView for long/short versions; this is easier than manually
  calling ExpressionPrinter in the debugger.
  • Loading branch information
roji committed Jun 15, 2023
1 parent ef30eb2 commit 98b2f5e
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
/// not used in application code.
/// </para>
/// </summary>
#if DEBUG
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
#endif
public class OrderingExpression : Expression, IPrintableExpression
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
/// application or provider, then please file an issue at
/// <see href="https://github.com/dotnet/efcore">github.com/dotnet/efcore</see>.
/// </remarks>
#if DEBUG
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
#endif
public sealed class ProjectionExpression : Expression, IPrintableExpression
{
internal ProjectionExpression(SqlExpression expression, string alias)
Expand Down Expand Up @@ -57,6 +60,7 @@ public ProjectionExpression Update(SqlExpression expression)
void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
{
expressionPrinter.Visit(Expression);

if (Alias != string.Empty
&& !(Expression is ColumnExpression column
&& column.Name == Alias))
Expand Down
40 changes: 36 additions & 4 deletions src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
/// an issue at <see href="https://github.com/dotnet/efcore">github.com/dotnet/efcore</see>.
/// </remarks>
// Class is sealed because there are no public/protected constructors. Can be unsealed if this is changed.
[DebuggerDisplay("{PrintShortSql(), nq}")]
public sealed partial class SelectExpression : TableExpressionBase
{
private const string DiscriminatorColumnAlias = "Discriminator";
Expand Down Expand Up @@ -4561,6 +4562,13 @@ public override IEnumerable<IAnnotation> GetAnnotations()

/// <inheritdoc />
protected override void Print(ExpressionPrinter expressionPrinter)
{
PrintProjections(expressionPrinter);
expressionPrinter.AppendLine();
PrintSql(expressionPrinter);
}

private void PrintProjections(ExpressionPrinter expressionPrinter)
{
if (_clientProjections.Count > 0)
{
Expand Down Expand Up @@ -4588,12 +4596,16 @@ protected override void Print(ExpressionPrinter expressionPrinter)
}
}
}
}

expressionPrinter.AppendLine();

foreach (var tag in Tags)
private void PrintSql(ExpressionPrinter expressionPrinter, bool withTags = true)
{
if (withTags)
{
expressionPrinter.Append($"-- {tag}");
foreach (var tag in Tags)
{
expressionPrinter.Append($"-- {tag}");
}
}

IDisposable? indent = null;
Expand Down Expand Up @@ -4682,6 +4694,26 @@ protected override void Print(ExpressionPrinter expressionPrinter)
}
}

private string PrintShortSql()
{
var expressionPrinter = new ExpressionPrinter();
PrintSql(expressionPrinter, withTags: false);
return expressionPrinter.ToString();
}

/// <summary>
/// <para>
/// Expand this property in the debugger for a human-readable representation of this <see cref="SelectExpression" />.
/// </para>
/// <para>
/// Warning: Do not rely on the format of the debug strings.
/// They are designed for debugging only and may change arbitrarily between releases.
/// </para>
/// </summary>
[EntityFrameworkInternal]
public DebugView DebugView
=> new(PrintShortSql, () => this.Print());

/// <inheritdoc />
public override bool Equals(object? obj)
=> obj != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
/// </para>
/// </summary>
#if DEBUG
[DebuggerDisplay("{new Microsoft.EntityFrameworkCore.Query.ExpressionPrinter().PrintExpression(this), nq}")]
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
#endif
public abstract class SqlExpression : Expression, IPrintableExpression
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
/// not used in application code.
/// </para>
/// </summary>
#if DEBUG
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
#endif
public abstract class TableExpressionBase : Expression, IPrintableExpression
{
private readonly IReadOnlyDictionary<string, IAnnotation>? _annotations;
Expand Down
18 changes: 12 additions & 6 deletions src/EFCore/Query/ExpressionPrinter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,22 @@ private string PrintCore(Expression expression, int? characterLimit = null, bool

Visit(expression);

var queryPlan = PostProcess(_stringBuilder.ToString());
return ToString();
}

/// <inheritdoc />
public override string ToString()
{
var printed = PostProcess(_stringBuilder.ToString());

if (characterLimit is > 0)
if (CharacterLimit is > 0)
{
queryPlan = queryPlan.Length > characterLimit
? queryPlan[..characterLimit.Value] + "..."
: queryPlan;
printed = printed.Length > CharacterLimit
? printed[..CharacterLimit.Value] + "..."
: printed;
}

return queryPlan;
return printed;
}

/// <summary>
Expand Down

0 comments on commit 98b2f5e

Please sign in to comment.