Skip to content

Commit

Permalink
Generate compiled relational model
Browse files Browse the repository at this point in the history
Fixes #24896
  • Loading branch information
AndriySvyryd committed Feb 21, 2023
1 parent def962e commit b342b84
Show file tree
Hide file tree
Showing 10 changed files with 698 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,7 @@ private string CreateModelBuilder(
var methods = methodBuilder.ToString();
if (!string.IsNullOrEmpty(methods))
{
mainBuilder.AppendLine()
.AppendLines(methods);
mainBuilder.AppendLines(methods);
}
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ protected override void InitializeModel(IModel model, bool designTime, bool prev
{
model.SetRuntimeAnnotation(RelationalAnnotationNames.ModelDependencies, RelationalDependencies.RelationalModelDependencies);
}
else
else if (model.FindRuntimeAnnotation(RelationalAnnotationNames.RelationalModel) == null)
{
RelationalModel.Add(
model,
Expand Down
11 changes: 11 additions & 0 deletions src/EFCore.Relational/Metadata/Internal/Column.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ public virtual ColumnAccessors Accessors
ref _accessors, this, static column =>
ColumnAccessorsFactory.Create(column));

/// <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 void SetAccessors(ColumnAccessors accessors)
{
_accessors = accessors;
}

/// <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
14 changes: 10 additions & 4 deletions src/EFCore.Relational/Metadata/Internal/JsonColumn.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Json;
using Microsoft.EntityFrameworkCore.Internal;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace Microsoft.EntityFrameworkCore.Metadata.Internal;

/// <summary>
Expand All @@ -11,18 +15,18 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal;
/// </summary>
public class JsonColumn : Column, IColumn
{
private readonly ValueComparer _providerValueComparer;
private ValueComparer? _providerValueComparer;

/// <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 JsonColumn(string name, string type, Table table, ValueComparer provierValueComparer)
public JsonColumn(string name, string type, Table table, ValueComparer? providerValueComparer = null)
: base(name, type, table)
{
_providerValueComparer = provierValueComparer;
_providerValueComparer = providerValueComparer;
}

/// <summary>
Expand Down Expand Up @@ -149,7 +153,9 @@ bool IColumn.IsRowVersion
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
ValueComparer IColumnBase.ProviderValueComparer
=> _providerValueComparer;
=> NonCapturingLazyInitializer.EnsureInitialized(
ref _providerValueComparer, this, static column =>
column.Table.Model.Model.GetModelDependencies().TypeMappingSource.FindMapping(typeof(JsonElement)));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
88 changes: 64 additions & 24 deletions src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Data;
using System.Text.Json;

namespace Microsoft.EntityFrameworkCore.Metadata.Internal;
Expand Down Expand Up @@ -476,6 +477,8 @@ private static void CreateTableMapping(
// if navigation is defined on a derived type, the column must be made nullable
jsonColumn.IsNullable = true;
}

// TODO: Store on the dependent entity type
}
}
else
Expand Down Expand Up @@ -506,15 +509,7 @@ private static void CreateTableMapping(
var columnMapping = new ColumnMapping(property, column, tableMapping);
tableMapping.AddColumnMapping(columnMapping);
column.AddPropertyMapping(columnMapping);

if (property.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableColumnMappings)
is not SortedSet<ColumnMapping> columnMappings)
{
columnMappings = new SortedSet<ColumnMapping>(ColumnMappingBaseComparer.Instance);
property.AddRuntimeAnnotation(RelationalAnnotationNames.TableColumnMappings, columnMappings);
}

columnMappings.Add(columnMapping);
GetOrCreateColumnMappings(property).Add(columnMapping);
}
}

Expand Down Expand Up @@ -1683,18 +1678,11 @@ private static void PopulateForeignKeyConstraints(Table table)
continue;
}

var foreignKeyConstraints = foreignKey.FindRuntimeAnnotationValue(RelationalAnnotationNames.ForeignKeyMappings)
as SortedSet<ForeignKeyConstraint>;
var constraint = table.ForeignKeyConstraints.FirstOrDefault(fk => fk.Name == name);
if (constraint != null)
{
if (foreignKeyConstraints == null)
{
foreignKeyConstraints = new SortedSet<ForeignKeyConstraint>(ForeignKeyConstraintComparer.Instance);
foreignKey.AddRuntimeAnnotation(RelationalAnnotationNames.ForeignKeyMappings, foreignKeyConstraints);
}

foreignKeyConstraints.Add(constraint);
GetOrCreateForeignKeyConstraints(foreignKey).Add(constraint);

constraint.MappedForeignKeys.Add(foreignKey);
break;
Expand Down Expand Up @@ -1764,13 +1752,7 @@ private static void PopulateForeignKeyConstraints(Table table)
name, table, principalTable, columns, principalUniqueConstraint, ToReferentialAction(foreignKey.DeleteBehavior));
constraint.MappedForeignKeys.Add(foreignKey);

if (foreignKeyConstraints == null)
{
foreignKeyConstraints = new SortedSet<ForeignKeyConstraint>(ForeignKeyConstraintComparer.Instance);
foreignKey.AddRuntimeAnnotation(RelationalAnnotationNames.ForeignKeyMappings, foreignKeyConstraints);
}

foreignKeyConstraints.Add(constraint);
GetOrCreateForeignKeyConstraints(foreignKey).Add(constraint);
table.ForeignKeyConstraints.Add(constraint);
principalTable.ReferencingForeignKeyConstraints.Add(constraint);
break;
Expand All @@ -1779,6 +1761,64 @@ private static void PopulateForeignKeyConstraints(Table table)
}
}

/// <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 static SortedSet<ColumnMapping> GetOrCreateColumnMappings(IProperty property)
{
if (property.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableColumnMappings)
is not SortedSet<ColumnMapping> columnMappings)
{
columnMappings = new SortedSet<ColumnMapping>(ColumnMappingBaseComparer.Instance);
property.AddRuntimeAnnotation(RelationalAnnotationNames.TableColumnMappings, columnMappings);
}

return columnMappings;
}

/// <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 static SortedSet<ForeignKeyConstraint> GetOrCreateForeignKeyConstraints(IForeignKey foreignKey)
{
if (foreignKey.FindRuntimeAnnotationValue(RelationalAnnotationNames.ForeignKeyMappings)
is not SortedSet<ForeignKeyConstraint> foreignKeyConstraints)
{
foreignKeyConstraints = new SortedSet<ForeignKeyConstraint>(ForeignKeyConstraintComparer.Instance);
foreignKey.AddRuntimeAnnotation(RelationalAnnotationNames.ForeignKeyMappings, foreignKeyConstraints);
}

return foreignKeyConstraints;
}

/// <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 static IForeignKey GetForeignKey(
IModel model,
string declaringEntityTypeName,
IReadOnlyList<string> properties,
string principalEntityTypeName,
IReadOnlyList<string> principalProperties)
{
var declaringEntityType = model.FindEntityType(declaringEntityTypeName)!;
var principalEntityType = model.FindEntityType(principalEntityTypeName)!;

return declaringEntityType.FindForeignKey(
properties.Select(p => declaringEntityType.FindProperty(p)!).ToArray(),
principalEntityType.FindKey(principalProperties.Select(p => principalEntityType.FindProperty(p)!).ToArray())!,
principalEntityType)!;
}

/// <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
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ public override void Generate(IModel model, CSharpRuntimeAnnotationCodeGenerator
base.Generate(model, parameters);
}

/// <inheritdoc />
public override void Generate(IRelationalModel model, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
if (!parameters.IsRuntime)
{
var annotations = parameters.Annotations;
annotations.Remove(SqlServerAnnotationNames.MemoryOptimized);
annotations.Remove(SqlServerAnnotationNames.EditionOptions);
}

base.Generate(model, parameters);
}

/// <inheritdoc />
public override void Generate(IProperty property, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
Expand All @@ -63,6 +76,24 @@ public override void Generate(IProperty property, CSharpRuntimeAnnotationCodeGen
base.Generate(property, parameters);
}

/// <inheritdoc />
public override void Generate(IColumn column, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
if (!parameters.IsRuntime)
{
var annotations = parameters.Annotations;
annotations.Remove(SqlServerAnnotationNames.Identity);
annotations.Remove(SqlServerAnnotationNames.Sparse);
annotations.Remove(SqlServerAnnotationNames.IsTemporal);
annotations.Remove(SqlServerAnnotationNames.TemporalHistoryTableName);
annotations.Remove(SqlServerAnnotationNames.TemporalHistoryTableSchema);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodStartColumnName);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodEndColumnName);
}

base.Generate(column, parameters);
}

/// <inheritdoc />
public override void Generate(IIndex index, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
Expand All @@ -78,6 +109,21 @@ public override void Generate(IIndex index, CSharpRuntimeAnnotationCodeGenerator
base.Generate(index, parameters);
}

/// <inheritdoc />
public override void Generate(ITableIndex index, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
if (!parameters.IsRuntime)
{
var annotations = parameters.Annotations;
annotations.Remove(SqlServerAnnotationNames.Clustered);
annotations.Remove(SqlServerAnnotationNames.CreatedOnline);
annotations.Remove(SqlServerAnnotationNames.Include);
annotations.Remove(SqlServerAnnotationNames.FillFactor);
}

base.Generate(index, parameters);
}

/// <inheritdoc />
public override void Generate(IKey key, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
Expand All @@ -90,6 +136,18 @@ public override void Generate(IKey key, CSharpRuntimeAnnotationCodeGeneratorPara
base.Generate(key, parameters);
}

/// <inheritdoc />
public override void Generate(IUniqueConstraint uniqueConstraint, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
if (!parameters.IsRuntime)
{
var annotations = parameters.Annotations;
annotations.Remove(SqlServerAnnotationNames.Clustered);
}

base.Generate(uniqueConstraint, parameters);
}

/// <inheritdoc />
public override void Generate(IEntityType entityType, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
Expand All @@ -98,15 +156,29 @@ public override void Generate(IEntityType entityType, CSharpRuntimeAnnotationCod
var annotations = parameters.Annotations;
annotations.Remove(SqlServerAnnotationNames.TemporalHistoryTableName);
annotations.Remove(SqlServerAnnotationNames.TemporalHistoryTableSchema);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodEndColumnName);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodEndPropertyName);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodStartColumnName);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodStartPropertyName);
}

base.Generate(entityType, parameters);
}

/// <inheritdoc />
public override void Generate(ITable table, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
if (!parameters.IsRuntime)
{
var annotations = parameters.Annotations;
annotations.Remove(SqlServerAnnotationNames.MemoryOptimized);
annotations.Remove(SqlServerAnnotationNames.TemporalHistoryTableName);
annotations.Remove(SqlServerAnnotationNames.TemporalHistoryTableSchema);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodEndColumnName);
annotations.Remove(SqlServerAnnotationNames.TemporalPeriodStartColumnName);
}

base.Generate(table, parameters);
}

/// <inheritdoc />
public override void Generate(IRelationalPropertyOverrides overrides, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ public SqliteCSharpRuntimeAnnotationCodeGenerator(
{
}

/// <inheritdoc />
public override void Generate(IModel model, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
var annotations = parameters.Annotations;
if (!parameters.IsRuntime)
{
annotations.Remove(SqliteAnnotationNames.InitSpatialMetaData);
}

base.Generate(model, parameters);
}

/// <inheritdoc />
public override void Generate(IProperty property, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
Expand All @@ -39,4 +51,17 @@ public override void Generate(IProperty property, CSharpRuntimeAnnotationCodeGen

base.Generate(property, parameters);
}

/// <inheritdoc />
public override void Generate(IColumn column, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
var annotations = parameters.Annotations;
if (!parameters.IsRuntime)
{
annotations.Remove(SqliteAnnotationNames.Autoincrement);
annotations.Remove(SqliteAnnotationNames.Srid);
}

base.Generate(column, parameters);
}
}
Loading

0 comments on commit b342b84

Please sign in to comment.