Skip to content

Commit 0d5edbb

Browse files
committed
Improve expression debugging
1 parent f414770 commit 0d5edbb

12 files changed

Lines changed: 69 additions & 30 deletions

File tree

src/EFCore.Relational/Query/JsonQueryExpression.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,10 @@ public virtual JsonQueryExpression MakeNullable()
212212
/// <inheritdoc />
213213
public virtual void Print(ExpressionPrinter expressionPrinter)
214214
{
215-
expressionPrinter.Append("JsonQueryExpression(");
216215
expressionPrinter.Visit(JsonColumn);
217-
expressionPrinter.Append($""", "{string.Join(".", Path.Select(e => e.ToString()))}")""");
216+
expressionPrinter
217+
.Append(" Q-> ")
218+
.Append(string.Join(".", Path.Select(e => e.ToString())));
218219
}
219220

220221
/// <inheritdoc />

src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
1212
/// not used in application code.
1313
/// </para>
1414
/// </summary>
15-
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
15+
[DebuggerDisplay("{TableAlias}.{Name}")]
1616
public abstract class ColumnExpression : SqlExpression
1717
{
1818
/// <summary>
@@ -64,7 +64,4 @@ protected override void Print(ExpressionPrinter expressionPrinter)
6464
expressionPrinter.Append(TableAlias).Append(".");
6565
expressionPrinter.Append(Name);
6666
}
67-
68-
private string DebuggerDisplay()
69-
=> $"{TableAlias}.{Name}";
7067
}

src/EFCore.Relational/Query/SqlExpressions/JsonScalarExpression.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,10 @@ public virtual JsonScalarExpression Update(SqlExpression json)
126126
/// <inheritdoc />
127127
protected override void Print(ExpressionPrinter expressionPrinter)
128128
{
129-
expressionPrinter.Append("JsonScalarExpression(column: ");
130129
expressionPrinter.Visit(Json);
131-
expressionPrinter.Append($""", "{string.Join(".", Path.Select(e => e.ToString()))}")""");
130+
expressionPrinter
131+
.Append(" -> ")
132+
.Append(string.Join(".", Path.Select(e => e.ToString())));
132133
}
133134

134135
/// <inheritdoc />

src/EFCore.Relational/Query/SqlExpressions/OrderingExpression.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
1212
/// not used in application code.
1313
/// </para>
1414
/// </summary>
15+
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
1516
public class OrderingExpression : Expression, IPrintableExpression
1617
{
1718
/// <summary>

src/EFCore.Relational/Query/SqlExpressions/ProjectionExpression.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
1212
/// application or provider, then please file an issue at
1313
/// <see href="https://github.com/dotnet/efcore">github.com/dotnet/efcore</see>.
1414
/// </remarks>
15+
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
1516
public sealed class ProjectionExpression : Expression, IPrintableExpression
1617
{
1718
internal ProjectionExpression(SqlExpression expression, string alias)
@@ -57,6 +58,7 @@ public ProjectionExpression Update(SqlExpression expression)
5758
void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
5859
{
5960
expressionPrinter.Visit(Expression);
61+
6062
if (Alias != string.Empty
6163
&& !(Expression is ColumnExpression column
6264
&& column.Name == Alias))

src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
2121
/// an issue at <see href="https://github.com/dotnet/efcore">github.com/dotnet/efcore</see>.
2222
/// </remarks>
2323
// Class is sealed because there are no public/protected constructors. Can be unsealed if this is changed.
24+
[DebuggerDisplay("{PrintShortSql(), nq}")]
2425
public sealed partial class SelectExpression : TableExpressionBase
2526
{
2627
private const string DiscriminatorColumnAlias = "Discriminator";
@@ -4561,6 +4562,13 @@ public override IEnumerable<IAnnotation> GetAnnotations()
45614562

45624563
/// <inheritdoc />
45634564
protected override void Print(ExpressionPrinter expressionPrinter)
4565+
{
4566+
PrintProjections(expressionPrinter);
4567+
expressionPrinter.AppendLine();
4568+
PrintSql(expressionPrinter);
4569+
}
4570+
4571+
private void PrintProjections(ExpressionPrinter expressionPrinter)
45644572
{
45654573
if (_clientProjections.Count > 0)
45664574
{
@@ -4588,12 +4596,16 @@ protected override void Print(ExpressionPrinter expressionPrinter)
45884596
}
45894597
}
45904598
}
4599+
}
45914600

4592-
expressionPrinter.AppendLine();
4593-
4594-
foreach (var tag in Tags)
4601+
private void PrintSql(ExpressionPrinter expressionPrinter, bool withTags = true)
4602+
{
4603+
if (withTags)
45954604
{
4596-
expressionPrinter.Append($"-- {tag}");
4605+
foreach (var tag in Tags)
4606+
{
4607+
expressionPrinter.Append($"-- {tag}");
4608+
}
45974609
}
45984610

45994611
IDisposable? indent = null;
@@ -4682,6 +4694,26 @@ protected override void Print(ExpressionPrinter expressionPrinter)
46824694
}
46834695
}
46844696

4697+
private string PrintShortSql()
4698+
{
4699+
var expressionPrinter = new ExpressionPrinter();
4700+
PrintSql(expressionPrinter, withTags: false);
4701+
return expressionPrinter.ToString();
4702+
}
4703+
4704+
/// <summary>
4705+
/// <para>
4706+
/// Expand this property in the debugger for a human-readable representation of this <see cref="SelectExpression" />.
4707+
/// </para>
4708+
/// <para>
4709+
/// Warning: Do not rely on the format of the debug strings.
4710+
/// They are designed for debugging only and may change arbitrarily between releases.
4711+
/// </para>
4712+
/// </summary>
4713+
[EntityFrameworkInternal]
4714+
public string DebugView
4715+
=> this.Print();
4716+
46854717
/// <inheritdoc />
46864718
public override bool Equals(object? obj)
46874719
=> obj != null

src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
1212
/// not used in application code.
1313
/// </para>
1414
/// </summary>
15-
#if DEBUG
16-
[DebuggerDisplay("{new Microsoft.EntityFrameworkCore.Query.ExpressionPrinter().PrintExpression(this), nq}")]
17-
#endif
15+
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
1816
public abstract class SqlExpression : Expression, IPrintableExpression
1917
{
2018
/// <summary>

src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions;
1212
/// not used in application code.
1313
/// </para>
1414
/// </summary>
15+
[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")]
1516
public abstract class TableExpressionBase : Expression, IPrintableExpression
1617
{
1718
private readonly IReadOnlyDictionary<string, IAnnotation>? _annotations;

src/EFCore/Query/ExpressionPrinter.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,22 @@ private string PrintCore(Expression expression, int? characterLimit = null, bool
166166

167167
Visit(expression);
168168

169-
var queryPlan = PostProcess(_stringBuilder.ToString());
169+
return ToString();
170+
}
171+
172+
/// <inheritdoc />
173+
public override string ToString()
174+
{
175+
var printed = PostProcess(_stringBuilder.ToString());
170176

171-
if (characterLimit is > 0)
177+
if (CharacterLimit is > 0)
172178
{
173-
queryPlan = queryPlan.Length > characterLimit
174-
? queryPlan[..characterLimit.Value] + "..."
175-
: queryPlan;
179+
printed = printed.Length > CharacterLimit
180+
? printed[..CharacterLimit.Value] + "..."
181+
: printed;
176182
}
177183

178-
return queryPlan;
184+
return printed;
179185
}
180186

181187
/// <summary>

src/EFCore/Query/ProjectionMember.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ namespace Microsoft.EntityFrameworkCore.Query;
1616
/// See <see href="https://aka.ms/efcore-docs-providers">Implementation of database providers and extensions</see>
1717
/// and <see href="https://aka.ms/efcore-docs-how-query-works">How EF Core queries work</see> for more information and examples.
1818
/// </remarks>
19-
[DebuggerDisplay("{ToString(), nq}")]
2019
public sealed class ProjectionMember
2120
{
2221
private readonly IList<MemberInfo> _memberChain;

0 commit comments

Comments
 (0)