Skip to content

Commit

Permalink
Add complex types to Metadata
Browse files Browse the repository at this point in the history
Fixes #13947
  • Loading branch information
AndriySvyryd committed Jun 17, 2023
1 parent ef30eb2 commit 00d261e
Show file tree
Hide file tree
Showing 262 changed files with 28,603 additions and 7,377 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace Microsoft.EntityFrameworkCore.Scaffolding.Internal;
Expand Down Expand Up @@ -459,6 +460,11 @@ private string GenerateEntityType(IEntityType entityType, string @namespace, str
{
CreateEntityType(entityType, mainBuilder, methodBuilder, namespaces, className, nullable);

foreach (var complexProperty in entityType.GetDeclaredComplexProperties())
{
CreateComplexProperty(complexProperty, mainBuilder, methodBuilder, namespaces, className, nullable);
}

var foreignKeyNumber = 1;
foreach (var foreignKey in entityType.GetDeclaredForeignKeys())
{
Expand Down Expand Up @@ -527,7 +533,7 @@ private void CreateEntityType(

Create(entityType, parameters);

var propertyVariables = new Dictionary<IProperty, string>();
var propertyVariables = new Dictionary<IPrimitivePropertyBase, string>();
foreach (var property in entityType.GetDeclaredProperties())
{
Create(property, propertyVariables, parameters);
Expand All @@ -538,6 +544,17 @@ private void CreateEntityType(
Create(property, parameters);
}

foreach (var complexProperty in entityType.GetDeclaredComplexProperties())
{
mainBuilder
.Append(_code.Identifier(complexProperty.Name, capitalize: true))
.Append("ComplexProperty")
.Append(".Create")
.Append("(")
.Append(entityTypeVariable)
.AppendLine(");");
}

foreach (var key in entityType.GetDeclaredKeys())
{
Create(key, propertyVariables, parameters, nullable);
Expand Down Expand Up @@ -663,7 +680,44 @@ private void Create(IEntityType entityType, CSharpRuntimeAnnotationCodeGenerator

private void Create(
IProperty property,
Dictionary<IProperty, string> propertyVariables,
Dictionary<IPrimitivePropertyBase, string> propertyVariables,
CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
var variableName = _code.Identifier(property.Name, parameters.ScopeVariables, capitalize: false);
propertyVariables[property] = variableName;

Create(property, variableName, propertyVariables, parameters);

CreateAnnotations(
property,
_annotationCodeGenerator.Generate,
parameters with { TargetName = variableName });

parameters.MainBuilder.AppendLine();
}

private void Create(
IComplexTypeProperty property,
Dictionary<IPrimitivePropertyBase, string> propertyVariables,
CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
var variableName = _code.Identifier(property.Name, parameters.ScopeVariables, capitalize: false);
propertyVariables[property] = variableName;

Create(property, variableName, propertyVariables, parameters);

CreateAnnotations(
property,
_annotationCodeGenerator.Generate,
parameters with { TargetName = variableName });

parameters.MainBuilder.AppendLine();
}

private void Create(
IPrimitivePropertyBase property,
string variableName,
Dictionary<IPrimitivePropertyBase, string> propertyVariables,
CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
var valueGeneratorFactoryType = (Type?)property[CoreAnnotationNames.ValueGeneratorFactoryType];
Expand All @@ -672,7 +726,7 @@ private void Create(
{
throw new InvalidOperationException(
DesignStrings.CompiledModelValueGenerator(
property.DeclaringEntityType.ShortName(), property.Name, nameof(PropertyBuilder.HasValueGeneratorFactory)));
property.DeclaringType.ShortName(), property.Name, nameof(PropertyBuilder.HasValueGeneratorFactory)));
}

var valueComparerType = (Type?)property[CoreAnnotationNames.ValueComparerType];
Expand All @@ -681,7 +735,7 @@ private void Create(
{
throw new InvalidOperationException(
DesignStrings.CompiledModelValueComparer(
property.DeclaringEntityType.ShortName(), property.Name, nameof(PropertyBuilder.HasConversion)));
property.DeclaringType.ShortName(), property.Name, nameof(PropertyBuilder.HasConversion)));
}

var providerValueComparerType = (Type?)property[CoreAnnotationNames.ProviderValueComparerType];
Expand All @@ -690,7 +744,7 @@ private void Create(
{
throw new InvalidOperationException(
DesignStrings.CompiledModelValueComparer(
property.DeclaringEntityType.ShortName(), property.Name, nameof(PropertyBuilder.HasConversion)));
property.DeclaringType.ShortName(), property.Name, nameof(PropertyBuilder.HasConversion)));
}

var valueConverterType = GetValueConverterType(property);
Expand All @@ -699,20 +753,17 @@ private void Create(
{
throw new InvalidOperationException(
DesignStrings.CompiledModelValueConverter(
property.DeclaringEntityType.ShortName(), property.Name, nameof(PropertyBuilder.HasConversion)));
property.DeclaringType.ShortName(), property.Name, nameof(PropertyBuilder.HasConversion)));
}

if (property is IConventionProperty conventionProperty
&& conventionProperty.GetTypeMappingConfigurationSource() != null)
{
throw new InvalidOperationException(
DesignStrings.CompiledModelTypeMapping(
property.DeclaringEntityType.ShortName(), property.Name, "Customize()", parameters.ClassName));
property.DeclaringType.ShortName(), property.Name, "Customize()", parameters.ClassName));
}

var variableName = _code.Identifier(property.Name, parameters.ScopeVariables, capitalize: false);
propertyVariables[property] = variableName;

var mainBuilder = parameters.MainBuilder;
mainBuilder
.Append("var ").Append(variableName).Append(" = ").Append(parameters.TargetName).AppendLine(".AddProperty(")
Expand Down Expand Up @@ -870,16 +921,9 @@ private void Create(
mainBuilder
.AppendLine(");")
.DecrementIndent();

CreateAnnotations(
property,
_annotationCodeGenerator.Generate,
parameters with { TargetName = variableName });

mainBuilder.AppendLine();
}

private static Type? GetValueConverterType(IProperty property)
private static Type? GetValueConverterType(IPrimitivePropertyBase property)
{
var annotation = property.FindAnnotation(CoreAnnotationNames.ValueConverterType);
if (annotation != null)
Expand Down Expand Up @@ -925,9 +969,8 @@ private void Create(
}

return i == ForeignKey.LongestFkChainAllowedLength
? throw new InvalidOperationException(
CoreStrings.RelationshipCycle(
property.DeclaringEntityType.DisplayName(), property.Name, "ValueConverterType"))
? throw new InvalidOperationException(CoreStrings.RelationshipCycle(
property.DeclaringType.DisplayName(), property.Name, "ValueConverterType"))
: null;
}

Expand Down Expand Up @@ -1004,7 +1047,7 @@ private void FindProperties(
IEnumerable<IProperty> properties,
IndentedStringBuilder mainBuilder,
bool nullable,
Dictionary<IProperty, string>? propertyVariables = null)
Dictionary<IPrimitivePropertyBase, string>? propertyVariables = null)
{
mainBuilder.Append("new[] { ");
var first = true;
Expand Down Expand Up @@ -1059,7 +1102,7 @@ private void Create(

mainBuilder
.AppendLine(",")
.Append("serviceType: typeof(" + property.ClrType.DisplayName(fullName: true, compilable: true) + ")");
.Append("serviceType: typeof(" + _code.Reference(property.ClrType) + ")");

mainBuilder
.AppendLine(");")
Expand All @@ -1075,7 +1118,7 @@ private void Create(

private void Create(
IKey key,
Dictionary<IProperty, string> propertyVariables,
Dictionary<IPrimitivePropertyBase, string> propertyVariables,
CSharpRuntimeAnnotationCodeGeneratorParameters parameters,
bool nullable)
{
Expand Down Expand Up @@ -1109,7 +1152,7 @@ private void Create(

private void Create(
IIndex index,
Dictionary<IProperty, string> propertyVariables,
Dictionary<IPrimitivePropertyBase, string> propertyVariables,
CSharpRuntimeAnnotationCodeGeneratorParameters parameters,
bool nullable)
{
Expand Down Expand Up @@ -1148,6 +1191,144 @@ private void Create(
mainBuilder.AppendLine();
}

private void CreateComplexProperty(
IComplexProperty complexProperty,
IndentedStringBuilder mainBuilder,
IndentedStringBuilder methodBuilder,
SortedSet<string> namespaces,
string topClassName,
bool nullable)
{
mainBuilder
.Append("private static class ")
.Append(_code.Identifier(complexProperty.Name, capitalize: true))
.Append("ComplexProperty")
.AppendLine("{");

var complexType = complexProperty.ComplexType;
using (mainBuilder.Indent())
{
var declaringTypeVariable = "declaringEntityType";
mainBuilder.AppendLine()
.Append("public static RuntimeComplexProperty Create")
.Append($"(RuntimeEntityType {declaringTypeVariable})")
.AppendLine("{");

using (mainBuilder.Indent())
{
const string complexPropertyVariable = "complexProperty";
var variables = new HashSet<string>
{
declaringTypeVariable,
complexPropertyVariable
};

mainBuilder
.Append("var ").Append(complexPropertyVariable).Append(" = ")
.Append(declaringTypeVariable).Append(".AddComplexProperty(")
.IncrementIndent()
.Append(_code.Literal(complexProperty.Name))
.AppendLine(",")
.Append(_code.Literal(complexProperty.ClrType));

AddNamespace(complexProperty.ClrType, namespaces);

var parameters = new CSharpRuntimeAnnotationCodeGeneratorParameters(
declaringTypeVariable,
topClassName,
mainBuilder,
methodBuilder,
namespaces,
variables,
nullable);

PropertyBaseParameters(complexProperty, parameters, skipType: true);

if (complexProperty.IsNullable)
{
mainBuilder.AppendLine(",")
.Append("nullable: ")
.Append(_code.Literal(true));
}

if (complexProperty.IsCollection)
{
mainBuilder.AppendLine(",")
.Append("collection: ")
.Append(_code.Literal(true));
}

var changeTrackingStrategy = complexType.GetChangeTrackingStrategy();
if (changeTrackingStrategy != ChangeTrackingStrategy.Snapshot)
{
namespaces.Add(typeof(ChangeTrackingStrategy).Namespace!);

mainBuilder.AppendLine(",")
.Append("changeTrackingStrategy: ")
.Append(_code.Literal(changeTrackingStrategy));
}

var indexerPropertyInfo = complexType.FindIndexerPropertyInfo();
if (indexerPropertyInfo != null)
{
mainBuilder.AppendLine(",")
.Append("indexerPropertyInfo: RuntimeEntityType.FindIndexerProperty(")
.Append(_code.Literal(complexType.ClrType))
.Append(")");
}

if (complexType.IsPropertyBag)
{
mainBuilder.AppendLine(",")
.Append("propertyBag: ")
.Append(_code.Literal(true));
}

mainBuilder
.AppendLine(");")
.AppendLine()
.DecrementIndent();

var complexPropertyParameters = parameters with { TargetName = complexPropertyVariable };
var propertyVariables = new Dictionary<IPrimitivePropertyBase, string>();
foreach (var property in complexType.GetProperties())
{
Create(property, propertyVariables, complexPropertyParameters);
}

foreach (var nestedComplexProperty in complexType.GetComplexProperties())
{
mainBuilder
.Append(_code.Identifier(nestedComplexProperty.Name, capitalize: true))
.Append("ComplexProperty")
.Append(".Create")
.Append("(")
.Append(complexPropertyVariable)
.AppendLine(");");
}

CreateAnnotations(
complexProperty,
_annotationCodeGenerator.Generate,
complexPropertyParameters);

mainBuilder
.Append("return ")
.Append(complexPropertyVariable)
.AppendLine(";");
}

mainBuilder.AppendLine("}");
}

foreach (var nestedComplexProperty in complexType.GetComplexProperties())
{
CreateComplexProperty(nestedComplexProperty, mainBuilder, methodBuilder, namespaces, topClassName, nullable);
}

mainBuilder.AppendLine("}");
}

private void CreateForeignKey(
IForeignKey foreignKey,
int foreignKeyNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,10 +714,10 @@ protected virtual ModelBuilder VisitForeignKeys(
uniquifier: NavigationUniquifier);

var leftSkipNavigation = leftEntityType.AddSkipNavigation(
leftNavigationPropertyName, null, rightEntityType, collection: true, onDependent: false);
leftNavigationPropertyName, memberInfo: null, targetEntityType: rightEntityType, collection: true, onDependent: false);
leftSkipNavigation.SetForeignKey(fks[0]);
var rightSkipNavigation = rightEntityType.AddSkipNavigation(
rightNavigationPropertyName, null, leftEntityType, collection: true, onDependent: false);
rightNavigationPropertyName, memberInfo: null, targetEntityType: leftEntityType, collection: true, onDependent: false);
rightSkipNavigation.SetForeignKey(fks[1]);
leftSkipNavigation.SetInverse(rightSkipNavigation);
rightSkipNavigation.SetInverse(leftSkipNavigation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

// ReSharper disable once CheckNamespace
Expand Down Expand Up @@ -1055,7 +1056,7 @@ public static void SetDefaultValue(this IMutableProperty property, object? value
/// </summary>
/// <param name="property">The property.</param>
/// <returns>A flag indicating whether the property is capable of storing only fixed-length data, such as strings.</returns>
public static bool? IsFixedLength(this IReadOnlyProperty property)
public static bool? IsFixedLength(this IReadOnlyPrimitivePropertyBase property)
=> (bool?)property.FindAnnotation(RelationalAnnotationNames.IsFixedLength)?.Value;

/// <summary>
Expand Down Expand Up @@ -1103,10 +1104,10 @@ public static void SetIsFixedLength(this IMutableProperty property, bool? fixedL
fromDataAnnotation)?.Value;

/// <summary>
/// Gets the <see cref="ConfigurationSource" /> for <see cref="IsFixedLength(IReadOnlyProperty)" />.
/// Gets the <see cref="ConfigurationSource" /> for <see cref="IsFixedLength(IReadOnlyPrimitivePropertyBase)" />.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>The <see cref="ConfigurationSource" /> for <see cref="IsFixedLength(IReadOnlyProperty)" />.</returns>
/// <returns>The <see cref="ConfigurationSource" /> for <see cref="IsFixedLength(IReadOnlyPrimitivePropertyBase)" />.</returns>
public static ConfigurationSource? GetIsFixedLengthConfigurationSource(this IConventionProperty property)
=> property.FindAnnotation(RelationalAnnotationNames.IsFixedLength)?.GetConfigurationSource();

Expand Down
Loading

0 comments on commit 00d261e

Please sign in to comment.