diff --git a/src/EFCore.Relational/Query/SqlExpressions/OrderingExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/OrderingExpression.cs index 768c68222b9..db0c8bb40cf 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/OrderingExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/OrderingExpression.cs @@ -12,6 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions; /// not used in application code. /// /// +#if DEBUG +[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")] +#endif public class OrderingExpression : Expression, IPrintableExpression { /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/ProjectionExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/ProjectionExpression.cs index 4a092975ad1..bc1d7becc10 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/ProjectionExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/ProjectionExpression.cs @@ -12,6 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions; /// application or provider, then please file an issue at /// github.com/dotnet/efcore. /// +#if DEBUG +[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")] +#endif public sealed class ProjectionExpression : Expression, IPrintableExpression { internal ProjectionExpression(SqlExpression expression, string alias) @@ -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)) diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index d515782c6df..7057d01825b 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -21,6 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions; /// an issue at github.com/dotnet/efcore. /// // 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"; @@ -4561,6 +4562,13 @@ public override IEnumerable GetAnnotations() /// protected override void Print(ExpressionPrinter expressionPrinter) + { + PrintProjections(expressionPrinter); + expressionPrinter.AppendLine(); + PrintSql(expressionPrinter); + } + + private void PrintProjections(ExpressionPrinter expressionPrinter) { if (_clientProjections.Count > 0) { @@ -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; @@ -4682,6 +4694,26 @@ protected override void Print(ExpressionPrinter expressionPrinter) } } + private string PrintShortSql() + { + var expressionPrinter = new ExpressionPrinter(); + PrintSql(expressionPrinter, withTags: false); + return expressionPrinter.ToString(); + } + + /// + /// + /// Expand this property in the debugger for a human-readable representation of this . + /// + /// + /// Warning: Do not rely on the format of the debug strings. + /// They are designed for debugging only and may change arbitrarily between releases. + /// + /// + [EntityFrameworkInternal] + public DebugView DebugView + => new(PrintShortSql, () => this.Print()); + /// public override bool Equals(object? obj) => obj != null diff --git a/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs index 8301f316dbb..0f11720d4a3 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs @@ -13,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions; /// /// #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 { diff --git a/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs b/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs index d535dc2a3ea..07ed28296e1 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs @@ -12,6 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions; /// not used in application code. /// /// +#if DEBUG +[DebuggerDisplay("{Microsoft.EntityFrameworkCore.Query.ExpressionPrinter.Print(this), nq}")] +#endif public abstract class TableExpressionBase : Expression, IPrintableExpression { private readonly IReadOnlyDictionary? _annotations; diff --git a/src/EFCore/Query/ExpressionPrinter.cs b/src/EFCore/Query/ExpressionPrinter.cs index dfee02d5868..5c51f71449c 100644 --- a/src/EFCore/Query/ExpressionPrinter.cs +++ b/src/EFCore/Query/ExpressionPrinter.cs @@ -166,16 +166,22 @@ private string PrintCore(Expression expression, int? characterLimit = null, bool Visit(expression); - var queryPlan = PostProcess(_stringBuilder.ToString()); + return ToString(); + } + + /// + 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; } ///