Skip to content

Commit

Permalink
Generate Accessors for shadow properties and columns (#33996)
Browse files Browse the repository at this point in the history
Generate RowValueFactories
Improve KeyValueFactories generation

Fixes #33874
  • Loading branch information
AndriySvyryd committed Jun 20, 2024
1 parent 9401b50 commit 4ade343
Show file tree
Hide file tree
Showing 112 changed files with 2,985 additions and 995 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Update.Internal;

namespace Microsoft.EntityFrameworkCore.Design.Internal;

Expand Down Expand Up @@ -378,18 +379,12 @@ private string GetOrCreate(
public virtual void Generate(ITableBase table, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
=> GenerateSimpleAnnotations(parameters);

private string GetOrCreate(
private string Create(
ITable table,
CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
var metadataVariables = parameters.ScopeVariables;
if (metadataVariables.TryGetValue(table, out var tableVariable))
{
return tableVariable;
}

var code = Dependencies.CSharpHelper;
tableVariable = code.Identifier(table.Name + "Table", table, parameters.ScopeObjects, capitalize: false);
var tableVariable = code.Identifier(table.Name + "Table", table, parameters.ScopeObjects, capitalize: false);
var mainBuilder = parameters.MainBuilder;
mainBuilder
.Append($"var {tableVariable} = new Table({code.Literal(table.Name)}, {code.Literal(table.Schema)}, ")
Expand All @@ -402,26 +397,6 @@ private string GetOrCreate(
Create(column, tableParameters);
}

foreach (var uniqueConstraint in table.UniqueConstraints)
{
Create(uniqueConstraint, uniqueConstraint.Columns.Select(c => metadataVariables[c]), tableParameters);
}

foreach (var index in table.Indexes)
{
Create(index, index.Columns.Select(c => metadataVariables[c]), tableParameters);
}

foreach (var trigger in table.Triggers)
{
var entityTypeVariable = metadataVariables[trigger.EntityType];

var triggerName = trigger.GetDatabaseName(StoreObjectIdentifier.Table(table.Name, table.Schema));
mainBuilder
.Append($"{tableVariable}.Triggers.Add({code.Literal(triggerName)}, ")
.AppendLine($"{entityTypeVariable}.FindDeclaredTrigger({code.Literal(trigger.ModelName)}));");
}

CreateAnnotations(
table,
Generate,
Expand Down Expand Up @@ -746,6 +721,13 @@ private void Create(
.AppendLine(";")
.AppendLine($"{parameters.TargetName}.Columns.Add({code.Literal(column.Name)}, {columnVariable});");

AddNamespace(typeof(ColumnAccessorsFactory), parameters.Namespaces);
AddNamespace(column.ProviderClrType, parameters.Namespaces);
var columnClrType = code.Reference(column.ProviderClrType);
mainBuilder
.Append(columnVariable).Append(".").Append(nameof(Column.Accessors)).Append(" = ")
.AppendLine($"{nameof(ColumnAccessorsFactory)}.CreateGeneric<{columnClrType}>({columnVariable});");

CreateAnnotations(
column,
Generate,
Expand Down Expand Up @@ -936,7 +918,7 @@ private void Create(
var uniqueConstraintVariable = code.Identifier(uniqueConstraint.Name, uniqueConstraint, parameters.ScopeObjects, capitalize: false);
var mainBuilder = parameters.MainBuilder;
mainBuilder
.Append("var ").Append(uniqueConstraintVariable).Append(" = new ").Append("UniqueConstraint").Append("(")
.Append("var ").Append(uniqueConstraintVariable).Append(" = new UniqueConstraint(")
.Append(code.Literal(uniqueConstraint.Name)).Append(", ")
.Append(parameters.TargetName).Append(", ")
.Append("new[] { ").AppendJoin(columns).AppendLine(" });");
Expand All @@ -947,6 +929,22 @@ private void Create(
.Append(parameters.TargetName).Append(".PrimaryKey = ").Append(uniqueConstraintVariable).AppendLine(";");
}

AddNamespace(typeof(CompositeRowKeyValueFactory), parameters.Namespaces);
mainBuilder
.Append(uniqueConstraintVariable).Append(".").Append(nameof(UniqueConstraint.SetRowKeyValueFactory)).Append("(");
if (uniqueConstraint.Columns.Count == 1)
{
var type = uniqueConstraint.Columns.First().ProviderClrType;
mainBuilder
.Append($"new SimpleRowKeyValueFactory<{code.Reference(type)}>({uniqueConstraintVariable})");
}
else
{
mainBuilder
.Append($"new CompositeRowKeyValueFactory({uniqueConstraintVariable})");
}
mainBuilder.AppendLine(");");

CreateAnnotations(
uniqueConstraint,
Generate,
Expand Down Expand Up @@ -997,6 +995,22 @@ private void Create(
.Append("new[] { ").AppendJoin(columns).Append(" }, ")
.Append(code.Literal(index.IsUnique)).AppendLine(");");

AddNamespace(typeof(CompositeRowIndexValueFactory), parameters.Namespaces);
mainBuilder
.Append(indexVariable).Append(".").Append(nameof(TableIndex.SetRowIndexValueFactory)).Append("(");
if (index.Columns.Count == 1)
{
var type = index.Columns.First().ProviderClrType;
mainBuilder
.Append($"new SimpleRowIndexValueFactory<{code.Reference(type)}>({indexVariable})");
}
else
{
mainBuilder
.Append($"new CompositeRowIndexValueFactory({indexVariable})");
}
mainBuilder.AppendLine(");");

CreateAnnotations(
index,
Generate,
Expand Down Expand Up @@ -1052,6 +1066,25 @@ private void Create(
.Append($"{principalTableVariable}.FindUniqueConstraint({code.Literal(foreignKey.PrincipalUniqueConstraint.Name)})!, ")
.Append(code.Literal(foreignKey.OnDeleteAction)).AppendLine(");").DecrementIndent();

AddNamespace(typeof(CompositeRowForeignKeyValueFactory), parameters.Namespaces);
mainBuilder
.Append(foreignKeyConstraintVariable).Append(".").Append(nameof(ForeignKeyConstraint.SetRowForeignKeyValueFactory)).Append("(");
var createRowForeignKeyValueFactoryMethod = "new CompositeRowForeignKeyValueFactory(";
if (foreignKey.Columns.Count == 1)
{
var principalColumn = foreignKey.PrincipalColumns.First();
var dependentColumn = foreignKey.Columns.First();
createRowForeignKeyValueFactoryMethod = principalColumn.ProviderClrType.IsNullableType() || principalColumn.IsNullable
? $"{nameof(RowForeignKeyValueFactoryFactory)}.{nameof(RowForeignKeyValueFactoryFactory.CreateSimpleNullableFactory)}"
: $"{nameof(RowForeignKeyValueFactoryFactory)}.{nameof(RowForeignKeyValueFactoryFactory.CreateSimpleNonNullableFactory)}";
createRowForeignKeyValueFactoryMethod +=
$"<{code.Reference(principalColumn.ProviderClrType)}, {code.Reference(dependentColumn.ProviderClrType)}>(";
}

mainBuilder
.Append($"{createRowForeignKeyValueFactoryMethod}{foreignKeyConstraintVariable})");
mainBuilder.AppendLine(");");

CreateAnnotations(
foreignKey,
Generate,
Expand Down Expand Up @@ -1149,7 +1182,12 @@ private void Create(
var typeBaseVariable = metadataVariables[typeBase];

var table = tableMapping.Table;
var tableVariable = GetOrCreate(table, parameters);
if (!parameters.ScopeVariables.TryGetValue(table, out var tableVariable))
{
tableVariable = Create(table, parameters);
}

var tableParameters = parameters with { TargetName = tableVariable };
var tableMappingVariable = code.Identifier(table.Name + "TableMapping", tableMapping, parameters.ScopeObjects, capitalize: false);

GenerateAddMapping(
Expand All @@ -1173,6 +1211,29 @@ private void Create(
.Append($"{typeBaseVariable}.FindProperty({code.Literal(columnMapping.Property.Name)})!, ")
.Append(tableMappingVariable).AppendLine(");");
}

if (tableMapping == table.EntityTypeMappings.Last())
{
foreach (var uniqueConstraint in table.UniqueConstraints)
{
Create(uniqueConstraint, uniqueConstraint.Columns.Select(c => metadataVariables[c]), tableParameters);
}

foreach (var index in table.Indexes)
{
Create(index, index.Columns.Select(c => metadataVariables[c]), tableParameters);
}

foreach (var trigger in table.Triggers)
{
var entityTypeVariable = metadataVariables[trigger.EntityType];

var triggerName = trigger.GetDatabaseName(StoreObjectIdentifier.Table(table.Name, table.Schema));
mainBuilder
.Append($"{tableVariable}.Triggers.Add({code.Literal(triggerName)}, ")
.AppendLine($"{entityTypeVariable}.FindDeclaredTrigger({code.Literal(trigger.ModelName)}));");
}
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@ public sealed record RelationalModelDependencies
public RelationalModelDependencies(
IRowKeyValueFactoryFactory rowKeyValueFactoryFactory,
IRowForeignKeyValueFactoryFactory foreignKeyRowValueFactorySource,
IRowIndexValueFactoryFactory rowIndexValueFactoryFactory)
IRowIndexValueFactoryFactory rowIndexValueFactoryFactory,
IValueConverterSelector valueConverterSelector)
{
RowKeyValueFactoryFactory = rowKeyValueFactoryFactory;
RowForeignKeyValueFactoryFactory = foreignKeyRowValueFactorySource;
RowIndexValueFactoryFactory = rowIndexValueFactoryFactory;
ValueConverterSelector = valueConverterSelector;
}

/// <summary>
Expand Down Expand Up @@ -83,4 +85,13 @@ public RelationalModelDependencies(
/// </summary>
[EntityFrameworkInternal]
public IRowIndexValueFactoryFactory RowIndexValueFactoryFactory { get; init; }

/// <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>
[EntityFrameworkInternal]
public IValueConverterSelector ValueConverterSelector { get; init; }
}
11 changes: 10 additions & 1 deletion src/EFCore.Relational/Metadata/Internal/ForeignKeyConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal;
/// </summary>
public class ForeignKeyConstraint : Annotatable, IForeignKeyConstraint
{
private IRowForeignKeyValueFactory? _foreignKeyRowValueFactory;

/// <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 @@ -100,7 +102,14 @@ public override bool IsReadOnly
/// <inheritdoc />
public virtual ReferentialAction OnDeleteAction { get; set; }

private IRowForeignKeyValueFactory? _foreignKeyRowValueFactory;
/// <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 void SetRowForeignKeyValueFactory(IRowForeignKeyValueFactory factory)
=> _foreignKeyRowValueFactory = factory;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
9 changes: 9 additions & 0 deletions src/EFCore.Relational/Metadata/Internal/TableIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ public virtual string? Filter

private IRowIndexValueFactory? _rowIndexValueFactory;

/// <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 void SetRowIndexValueFactory(IRowIndexValueFactory factory)
=> _rowIndexValueFactory = factory;

/// <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
19 changes: 9 additions & 10 deletions src/EFCore.Relational/Metadata/Internal/UniqueConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,22 @@ public override bool IsReadOnly
/// 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 IRowKeyValueFactory GetRowKeyValueFactory()
=> NonCapturingLazyInitializer.EnsureInitialized(
ref _rowKeyValueFactory, this,
static constraint =>
RuntimeFeature.IsDynamicCodeSupported
? constraint.Table.Model.Model.GetRelationalDependencies().RowKeyValueFactoryFactory.Create(constraint)
: throw new InvalidOperationException(CoreStrings.NativeAotNoCompiledModel));
public virtual void SetRowKeyValueFactory(IRowKeyValueFactory factory)
=> _rowKeyValueFactory = factory;

/// <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>
[EntityFrameworkInternal]
public virtual void SetRowKeyValueFactory(IRowKeyValueFactory factory)
=> _rowKeyValueFactory = factory;
public virtual IRowKeyValueFactory GetRowKeyValueFactory()
=> NonCapturingLazyInitializer.EnsureInitialized(
ref _rowKeyValueFactory, this,
static constraint =>
RuntimeFeature.IsDynamicCodeSupported
? constraint.Table.Model.Model.GetRelationalDependencies().RowKeyValueFactoryFactory.Create(constraint)
: throw new InvalidOperationException(CoreStrings.NativeAotNoCompiledModel));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Loading

0 comments on commit 4ade343

Please sign in to comment.