Skip to content

Commit

Permalink
Expose an annotation-free DebugView of the model
Browse files Browse the repository at this point in the history
This is mostly for me when debugging issues, since I frequently manually remove annotations to make the model easier to read.
  • Loading branch information
ajcvickers committed Nov 27, 2019
1 parent 20b72af commit 52751c2
Show file tree
Hide file tree
Showing 20 changed files with 193 additions and 59 deletions.
22 changes: 17 additions & 5 deletions src/EFCore/Metadata/Internal/DebugView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,25 @@ public class DebugView<TMetadata>
private readonly TMetadata _metadata;

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly Func<TMetadata, string> _toDebugString;
private readonly Func<TMetadata, string> _toShortDebugString;

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string _view;
private readonly Func<TMetadata, string> _toLongDebugString;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public DebugView([NotNull] TMetadata metadata, [NotNull] Func<TMetadata, string> toDebugString)
public DebugView(
[NotNull] TMetadata metadata,
[NotNull] Func<TMetadata, string> toShortDebugString,
[NotNull] Func<TMetadata, string> toLongDebugString)
{
_metadata = metadata;
_toDebugString = toDebugString;
_toShortDebugString = toShortDebugString;
_toLongDebugString = toLongDebugString;
}

/// <summary>
Expand All @@ -42,6 +46,14 @@ public DebugView([NotNull] TMetadata metadata, [NotNull] Func<TMetadata, string>
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual string View => _view ?? (_view = _toDebugString(_metadata));
public virtual string LongView => _toLongDebugString(_metadata);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual string ShortView => _toShortDebugString(_metadata);
}
}
65 changes: 65 additions & 0 deletions src/EFCore/Metadata/Internal/DebugViewOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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;

namespace Microsoft.EntityFrameworkCore.Metadata.Internal
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[Flags]
public enum DebugViewOptions
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
IncludeAnnotations = 1,

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
IncludePropertyIndexes = 2,

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
SingleLine = 4,

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
ShortDefault = 0,

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
LongDefault = IncludeAnnotations,

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
SingleLineDefault = SingleLine
}
}
7 changes: 5 additions & 2 deletions src/EFCore/Metadata/Internal/EntityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ private bool InheritsFrom(EntityType entityType)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public override string ToString() => this.ToDebugString();
public override string ToString() => this.ToDebugString(DebugViewOptions.SingleLineDefault);

/// <summary>
/// Runs the conventions when an annotation was set or removed.
Expand Down Expand Up @@ -3306,6 +3306,9 @@ public virtual void Attach([NotNull] InternalEntityTypeBuilder entityTypeBuilder
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual DebugView<EntityType> DebugView
=> new DebugView<EntityType>(this, m => m.ToDebugString(false));
=> new DebugView<EntityType>(
this,
m => m.ToDebugString(DebugViewOptions.ShortDefault),
m => m.ToDebugString(DebugViewOptions.LongDefault));
}
}
32 changes: 24 additions & 8 deletions src/EFCore/Metadata/Internal/EntityTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,10 @@ public static IEnumerable<IPropertyBase> GetNotificationProperties(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static string ToDebugString([NotNull] this IEntityType entityType, bool singleLine = true, [NotNull] string indent = "")
public static string ToDebugString(
[NotNull] this IEntityType entityType,
DebugViewOptions options,
[NotNull] string indent = "")
{
var builder = new StringBuilder();

Expand Down Expand Up @@ -510,15 +513,15 @@ public static string ToDebugString([NotNull] this IEntityType entityType, bool s
builder.Append(" ChangeTrackingStrategy.").Append(entityType.GetChangeTrackingStrategy());
}

if (!singleLine)
if ((options & DebugViewOptions.SingleLine) == 0)
{
var properties = entityType.GetDeclaredProperties().ToList();
if (properties.Count != 0)
{
builder.AppendLine().Append(indent).Append(" Properties: ");
foreach (var property in properties)
{
builder.AppendLine().Append(property.ToDebugString(singleLine: false, indent: indent + " "));
builder.AppendLine().Append(property.ToDebugString(options, indent + " "));
}
}

Expand All @@ -528,7 +531,7 @@ public static string ToDebugString([NotNull] this IEntityType entityType, bool s
builder.AppendLine().Append(indent).Append(" Navigations: ");
foreach (var navigation in navigations)
{
builder.AppendLine().Append(navigation.ToDebugString(singleLine: false, indent: indent + " "));
builder.AppendLine().Append(navigation.ToDebugString(options, indent + " "));
}
}

Expand All @@ -538,7 +541,7 @@ public static string ToDebugString([NotNull] this IEntityType entityType, bool s
builder.AppendLine().Append(indent).Append(" Service properties: ");
foreach (var serviceProperty in serviceProperties)
{
builder.AppendLine().Append(serviceProperty.ToDebugString(singleLine: false, indent: indent + " "));
builder.AppendLine().Append(serviceProperty.ToDebugString(options, indent + " "));
}
}

Expand All @@ -548,7 +551,7 @@ public static string ToDebugString([NotNull] this IEntityType entityType, bool s
builder.AppendLine().Append(indent).Append(" Keys: ");
foreach (var key in keys)
{
builder.AppendLine().Append(key.ToDebugString(singleLine: false, indent: indent + " "));
builder.AppendLine().Append(key.ToDebugString(options, indent + " "));
}
}

Expand All @@ -558,11 +561,24 @@ public static string ToDebugString([NotNull] this IEntityType entityType, bool s
builder.AppendLine().Append(indent).Append(" Foreign keys: ");
foreach (var fk in fks)
{
builder.AppendLine().Append(fk.ToDebugString(singleLine: false, indent: indent + " "));
builder.AppendLine().Append(fk.ToDebugString(options, indent + " "));
}
}

var indexes = entityType.GetDeclaredIndexes().ToList();
if (indexes.Count != 0)
{
builder.AppendLine().Append(indent).Append(" Indexes: ");
foreach (var index in indexes)
{
builder.AppendLine().Append(index.ToDebugString(options, indent + " "));
}
}

builder.Append(entityType.AnnotationsToDebugString(indent: indent + " "));
if ((options & DebugViewOptions.IncludeAnnotations) != 0)
{
builder.Append(entityType.AnnotationsToDebugString(indent: indent + " "));
}
}

return builder.ToString();
Expand Down
7 changes: 5 additions & 2 deletions src/EFCore/Metadata/Internal/ForeignKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,7 @@ void IConventionForeignKey.SetDeleteBehavior(DeleteBehavior? deleteBehavior, boo
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public override string ToString() => this.ToDebugString();
public override string ToString() => this.ToDebugString(DebugViewOptions.SingleLineDefault);

private void Validate(
IReadOnlyList<Property> properties,
Expand Down Expand Up @@ -1258,7 +1258,10 @@ private static bool ArePropertyTypesCompatible(
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual DebugView<ForeignKey> DebugView
=> new DebugView<ForeignKey>(this, m => m.ToDebugString(false));
=> new DebugView<ForeignKey>(
this,
m => m.ToDebugString(DebugViewOptions.ShortDefault),
m => m.ToDebugString(DebugViewOptions.LongDefault));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
9 changes: 7 additions & 2 deletions src/EFCore/Metadata/Internal/ForeignKeyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,16 @@ public static IDependentsMap CreateDependentsMapFactory([NotNull] this IForeignK
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static string ToDebugString([NotNull] this IForeignKey foreignKey, bool singleLine = true, [NotNull] string indent = "")
public static string ToDebugString(
[NotNull] this IForeignKey foreignKey,
DebugViewOptions options,
[NotNull] string indent = "")
{
var builder = new StringBuilder();

builder.Append(indent);

var singleLine = (options & DebugViewOptions.SingleLine) != 0;
if (singleLine)
{
builder.Append("ForeignKey: ");
Expand Down Expand Up @@ -310,7 +314,8 @@ public static string ToDebugString([NotNull] this IForeignKey foreignKey, bool s
builder.Append(" ToPrincipal: ").Append(foreignKey.DependentToPrincipal.Name);
}

if (!singleLine)
if (!singleLine &&
(options & DebugViewOptions.IncludeAnnotations) != 0)
{
builder.Append(foreignKey.AnnotationsToDebugString(indent + " "));
}
Expand Down
7 changes: 5 additions & 2 deletions src/EFCore/Metadata/Internal/Index.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public virtual INullableValueFactory<TKey> GetNullableValueFactory<TKey>()
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public override string ToString() => this.ToDebugString();
public override string ToString() => this.ToDebugString(DebugViewOptions.SingleLineDefault);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -182,7 +182,10 @@ public virtual INullableValueFactory<TKey> GetNullableValueFactory<TKey>()
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual DebugView<Index> DebugView
=> new DebugView<Index>(this, m => m.ToDebugString(false));
=> new DebugView<Index>(
this,
m => m.ToDebugString(DebugViewOptions.ShortDefault),
m => m.ToDebugString(DebugViewOptions.LongDefault));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
9 changes: 7 additions & 2 deletions src/EFCore/Metadata/Internal/IndexExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,16 @@ public static Index AsIndex([NotNull] this IIndex index, [NotNull] [CallerMember
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static string ToDebugString([NotNull] this IIndex index, bool singleLine = true, [NotNull] string indent = "")
public static string ToDebugString(
[NotNull] this IIndex index,
DebugViewOptions options,
[NotNull] string indent = "")
{
var builder = new StringBuilder();

builder.Append(indent);

var singleLine = (options & DebugViewOptions.SingleLine) != 0;
if (singleLine)
{
builder.Append("Index: ");
Expand All @@ -66,7 +70,8 @@ public static string ToDebugString([NotNull] this IIndex index, bool singleLine
builder.Append(" Unique");
}

if (!singleLine)
if (!singleLine &&
(options & DebugViewOptions.IncludeAnnotations) != 0)
{
builder.Append(index.AnnotationsToDebugString(indent + " "));
}
Expand Down
7 changes: 5 additions & 2 deletions src/EFCore/Metadata/Internal/Key.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public virtual IPrincipalKeyValueFactory<TKey> GetPrincipalKeyValueFactory<TKey>
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public override string ToString() => this.ToDebugString();
public override string ToString() => this.ToDebugString(DebugViewOptions.SingleLineDefault);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -166,7 +166,10 @@ public virtual IPrincipalKeyValueFactory<TKey> GetPrincipalKeyValueFactory<TKey>
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual DebugView<Key> DebugView
=> new DebugView<Key>(this, m => m.ToDebugString(false));
=> new DebugView<Key>(
this,
m => m.ToDebugString(DebugViewOptions.ShortDefault),
m => m.ToDebugString(DebugViewOptions.LongDefault));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
9 changes: 7 additions & 2 deletions src/EFCore/Metadata/Internal/KeyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,16 @@ public static int IndexOf([NotNull] this IKey key, [NotNull] IProperty property)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static string ToDebugString([NotNull] this IKey key, bool singleLine = true, [NotNull] string indent = "")
public static string ToDebugString(
[NotNull] this IKey key,
DebugViewOptions options,
[NotNull] string indent = "")
{
var builder = new StringBuilder();

builder.Append(indent);

var singleLine = (options & DebugViewOptions.SingleLine) != 0;
if (singleLine)
{
builder.Append("Key: ");
Expand All @@ -81,7 +85,8 @@ public static string ToDebugString([NotNull] this IKey key, bool singleLine = tr
builder.Append(" PK");
}

if (!singleLine)
if (!singleLine &&
(options & DebugViewOptions.IncludeAnnotations) != 0)
{
builder.Append(key.AnnotationsToDebugString(indent + " "));
}
Expand Down
Loading

0 comments on commit 52751c2

Please sign in to comment.