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

Add a pubternal way to namespace-qualify ambiguous types in compiled model. #25605

Merged
merged 1 commit into from
Aug 20, 2021
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
39 changes: 28 additions & 11 deletions src/EFCore.Design/Design/Internal/CSharpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,33 @@ public virtual string Lambda(IReadOnlyList<string> properties, string? lambdaIde
/// 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 Reference(Type type)
=> Reference(type, useFullName: false);

private string Reference(Type type, bool useFullName)
public virtual string Reference(Type type, bool? fullName = null)
{
Check.NotNull(type, nameof(type));

return type.DisplayName(fullName: useFullName, compilable: true);
fullName ??= type.IsNested ? ShouldUseFullName(type.DeclaringType!) : ShouldUseFullName(type);

return type.DisplayName(fullName.Value, compilable: true);
}

/// <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 bool ShouldUseFullName(Type type)
=> ShouldUseFullName(type.Name);

/// <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 bool ShouldUseFullName(string shortTypeName)
=> false;

/// <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
Expand Down Expand Up @@ -536,8 +553,8 @@ public virtual string Literal(BigInteger value)
/// 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 Literal(Type value)
=> $"typeof({Reference(value)})";
public virtual string Literal(Type value, bool? useFullName = null)
=> $"typeof({Reference(value, useFullName)})";

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -845,14 +862,14 @@ private bool HandleExpression(Expression expression, StringBuilder builder, bool
case ExpressionType.Convert:
builder
.Append('(')
.Append(Reference(expression.Type, useFullName: true))
.Append(Reference(expression.Type, fullName: true))
.Append(')');

return HandleExpression(((UnaryExpression)expression).Operand, builder);
case ExpressionType.New:
builder
.Append("new ")
.Append(Reference(expression.Type, useFullName: true));
.Append(Reference(expression.Type, fullName: true));

return HandleArguments(((NewExpression)expression).Arguments, builder);
case ExpressionType.Call:
Expand All @@ -861,7 +878,7 @@ private bool HandleExpression(Expression expression, StringBuilder builder, bool
if (callExpression.Method.IsStatic)
{
builder
.Append(Reference(callExpression.Method.DeclaringType!, useFullName: true));
.Append(Reference(callExpression.Method.DeclaringType!, fullName: true));
}
else
{
Expand Down Expand Up @@ -895,7 +912,7 @@ private bool HandleExpression(Expression expression, StringBuilder builder, bool
if (memberExpression.Expression == null)
{
builder
.Append(Reference(memberExpression.Member.DeclaringType!, useFullName: true));
.Append(Reference(memberExpression.Member.DeclaringType!, fullName: true));
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public virtual void Generate(string modelBuilderName, IModel model, IndentedStri
/// <param name="stringBuilder"> The builder code is added to. </param>
protected virtual void GenerateEntityTypes(
string modelBuilderName,
IReadOnlyList<IEntityType> entityTypes,
IEnumerable<IEntityType> entityTypes,
IndentedStringBuilder stringBuilder)
{
Check.NotEmpty(modelBuilderName, nameof(modelBuilderName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,10 @@ private string CreateModelBuilder(
var entityTypes = model.GetEntityTypesInHierarchicalOrder();
var variables = new HashSet<string>();

var anyEntityTypes = false;
foreach (var entityType in entityTypes)
{
anyEntityTypes = true;
var variableName = _code.Identifier(entityType.ShortName(), variables, capitalize: false);

var firstChar = variableName[0] == '@' ? variableName[1] : variableName[0];
Expand Down Expand Up @@ -265,7 +267,7 @@ private string CreateModelBuilder(
.AppendLine(");");
}

if (entityTypes.Count > 0)
if (anyEntityTypes)
{
mainBuilder.AppendLine();
}
Expand Down Expand Up @@ -339,7 +341,7 @@ private string CreateModelBuilder(
.AppendLine(");");
}

if (entityTypes.Count > 0)
if (anyEntityTypes)
{
mainBuilder.AppendLine();
}
Expand Down
6 changes: 4 additions & 2 deletions src/EFCore/Design/ICSharpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,9 @@ string Literal<T>(T? value)
/// Generates a <see cref="Type"/> literal.
/// </summary>
/// <param name="value"> The value. </param>
/// <param name="fullName"> Whether the type should be namespace-qualified. </param>
/// <returns> The literal. </returns>
string Literal(Type value);
string Literal(Type value, bool? fullName = null);

/// <summary>
/// Generates an object array literal.
Expand All @@ -228,8 +229,9 @@ string Literal<T>(T? value)
/// Generates a C# type reference.
/// </summary>
/// <param name="type"> The type to reference. </param>
/// <param name="fullName"> Whether the type should be namespace-qualified. </param>
/// <returns> The reference. </returns>
string Reference(Type type);
string Reference(Type type, bool? fullName = null);

/// <summary>
/// Generates a literal for a type not known at compile time.
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Metadata/Conventions/RuntimeModelConvention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected virtual RuntimeModel Create(IModel model)
((IModel)runtimeModel).ModelDependencies = model.ModelDependencies!;

var entityTypes = model.GetEntityTypesInHierarchicalOrder();
var entityTypePairs = new List<(IEntityType Source, RuntimeEntityType Target)>(entityTypes.Count);
var entityTypePairs = new List<(IEntityType Source, RuntimeEntityType Target)>();

foreach (var entityType in entityTypes)
{
Expand Down
6 changes: 3 additions & 3 deletions src/EFCore/Metadata/Internal/ModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ public static IEnumerable<IEntityType> GetRootEntityTypes(this IModel model)
/// 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 IReadOnlyList<IEntityType> GetEntityTypesInHierarchicalOrder(this IModel model)
public static IEnumerable<IEntityType> GetEntityTypesInHierarchicalOrder(this IModel model)
=> Sort(model.GetEntityTypes());

private static IReadOnlyList<IEntityType> Sort(IEnumerable<IEntityType> entityTypes)
private static IEnumerable<IEntityType> Sort(IEnumerable<IEntityType> entityTypes)
{
var entityTypeGraph = new Multigraph<IEntityType, int>();
entityTypeGraph.AddVertices(entityTypes);
Expand All @@ -52,7 +52,7 @@ private static IReadOnlyList<IEntityType> Sort(IEnumerable<IEntityType> entityTy
entityTypeGraph.AddEdge(entityType.BaseType!, entityType, 0);
}

return entityTypeGraph.TopologicalSort();
return entityTypeGraph.BatchingTopologicalSort().SelectMany(b => b.OrderBy(et => et.Name));
}

/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Shared/SharedTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,10 @@ public static IEnumerable<MemberInfo> GetMembersInHierarchy(this Type type, stri
#pragma warning disable IDE0034 // Simplify 'default' expression - default causes default(object)
{ typeof(int), default(int) },
{ typeof(Guid), default(Guid) },
{ typeof(DateOnly), default(DateOnly) },
{ typeof(DateTime), default(DateTime) },
{ typeof(DateTimeOffset), default(DateTimeOffset) },
{ typeof(TimeOnly), default(TimeOnly) },
{ typeof(long), default(long) },
{ typeof(bool), default(bool) },
{ typeof(double), default(double) },
Expand Down
Loading