Skip to content

Commit

Permalink
Add TableIndex and UniqueConstraint to the relational model.
Browse files Browse the repository at this point in the history
Part of #12846
  • Loading branch information
AndriySvyryd committed Mar 6, 2020
1 parent 9655da8 commit afe9774
Show file tree
Hide file tree
Showing 29 changed files with 942 additions and 51 deletions.
59 changes: 44 additions & 15 deletions src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ protected virtual void GenerateKeys(
foreach (var key in keys.Where(
key => key != primaryKey
&& (!key.GetReferencingForeignKeys().Any()
|| key.GetAnnotations().Any())))
|| key.GetAnnotations().Any(a => a.Name != RelationalAnnotationNames.UniqueConstraintMappings))))
{
GenerateKey(builderName, key, stringBuilder);
}
Expand Down Expand Up @@ -679,17 +679,31 @@ protected virtual void GenerateKey(

using (stringBuilder.Indent())
{
var annotations = key.GetAnnotations().ToList();

GenerateFluentApiForAnnotation(
ref annotations, RelationalAnnotationNames.Name, nameof(RelationalKeyBuilderExtensions.HasName), stringBuilder);

GenerateAnnotations(annotations, stringBuilder);
GenerateKeyAnnotations(key, stringBuilder);
}

stringBuilder.AppendLine(";");
}

/// <summary>
/// Generates code for the annotations on a key.
/// </summary>
/// <param name="key"> The key. </param>
/// <param name="stringBuilder"> The builder code is added to. </param>
protected virtual void GenerateKeyAnnotations([NotNull] IKey key, [NotNull] IndentedStringBuilder stringBuilder)
{
var annotations = key.GetAnnotations().ToList();

IgnoreAnnotations(
annotations,
RelationalAnnotationNames.UniqueConstraintMappings);

GenerateFluentApiForAnnotation(
ref annotations, RelationalAnnotationNames.Name, nameof(RelationalKeyBuilderExtensions.HasName), stringBuilder);

GenerateAnnotations(annotations, stringBuilder);
}

/// <summary>
/// Generates code for <see cref="IIndex" /> objects.
/// </summary>
Expand Down Expand Up @@ -742,19 +756,34 @@ protected virtual void GenerateIndex(
.Append(".IsUnique()");
}

var annotations = index.GetAnnotations().ToList();

GenerateFluentApiForAnnotation(
ref annotations, RelationalAnnotationNames.Name, nameof(RelationalIndexBuilderExtensions.HasName), stringBuilder);
GenerateFluentApiForAnnotation(
ref annotations, RelationalAnnotationNames.Filter, nameof(RelationalIndexBuilderExtensions.HasFilter), stringBuilder);

GenerateAnnotations(annotations, stringBuilder);
GenerateIndexAnnotations(index, stringBuilder);
}

stringBuilder.AppendLine(";");
}

/// <summary>
/// Generates code for the annotations on an index.
/// </summary>
/// <param name="index"> The index. </param>
/// <param name="stringBuilder"> The builder code is added to. </param>
protected virtual void GenerateIndexAnnotations(
[NotNull] IIndex index, [NotNull] IndentedStringBuilder stringBuilder)
{
var annotations = index.GetAnnotations().ToList();

IgnoreAnnotations(
annotations,
RelationalAnnotationNames.TableIndexMappings);

GenerateFluentApiForAnnotation(
ref annotations, RelationalAnnotationNames.Name, nameof(RelationalIndexBuilderExtensions.HasName), stringBuilder);
GenerateFluentApiForAnnotation(
ref annotations, RelationalAnnotationNames.Filter, nameof(RelationalIndexBuilderExtensions.HasFilter), stringBuilder);

GenerateAnnotations(annotations, stringBuilder);
}

/// <summary>
/// Generates code for the annotations on an entity type.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ private IEnumerable<string> GetAnnotationNamespaces(IEnumerable<IAnnotatable> it
RelationalAnnotationNames.Views,
RelationalAnnotationNames.ViewMappings,
RelationalAnnotationNames.ViewColumnMappings,
RelationalAnnotationNames.ForeignKeyMappings
RelationalAnnotationNames.ForeignKeyMappings,
RelationalAnnotationNames.TableIndexMappings,
RelationalAnnotationNames.UniqueConstraintMappings
};

return items.SelectMany(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ private void GenerateKey(IKey key, IEntityType entityType, bool useDataAnnotatio

var explicitName = key.GetName() != key.GetDefaultName();
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Name);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.UniqueConstraintMappings);

if (key.Properties.Count == 1
&& annotations.Count == 0)
Expand Down Expand Up @@ -578,6 +579,8 @@ private void GenerateIndex(IIndex index)

var annotations = index.GetAnnotations().ToList();

RemoveAnnotation(ref annotations, RelationalAnnotationNames.TableIndexMappings);

if (!string.IsNullOrEmpty((string)index[RelationalAnnotationNames.Name]))
{
lines.Add(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public static void SetConstraintName(
/// </summary>
/// <param name="foreignKey"> The foreign key. </param>
/// <returns> The foreign key constraints to which the foreign key is mapped. </returns>
public static IEnumerable<IForeignKeyConstraint> GetConstraintMappings([NotNull] this IForeignKey foreignKey) =>
public static IEnumerable<IForeignKeyConstraint> GetMappedConstraints([NotNull] this IForeignKey foreignKey) =>
(IEnumerable<IForeignKeyConstraint>)foreignKey[RelationalAnnotationNames.ForeignKeyMappings]
?? Enumerable.Empty<IForeignKeyConstraint>();
}
Expand Down
10 changes: 10 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
Expand Down Expand Up @@ -109,5 +110,14 @@ public static void SetFilter([NotNull] this IConventionIndex index, [CanBeNull]
/// <returns> The <see cref="ConfigurationSource" /> for the index filter expression. </returns>
public static ConfigurationSource? GetFilterConfigurationSource([NotNull] this IConventionIndex index)
=> index.FindAnnotation(RelationalAnnotationNames.Filter)?.GetConfigurationSource();

/// <summary>
/// Gets the table indexes to which the index is mapped.
/// </summary>
/// <param name="index"> The index. </param>
/// <returns> The table indexes to which the index is mapped. </returns>
public static IEnumerable<ITableIndex> GetMappedTableIndexes([NotNull] this IIndex index) =>
(IEnumerable<ITableIndex>)index[RelationalAnnotationNames.TableIndexMappings]
?? Enumerable.Empty<ITableIndex>();
}
}
10 changes: 10 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
Expand Down Expand Up @@ -88,5 +89,14 @@ public static void SetName([NotNull] this IConventionKey key, [CanBeNull] string
/// <returns> The <see cref="ConfigurationSource" /> for the constraint name. </returns>
public static ConfigurationSource? GetNameConfigurationSource([NotNull] this IConventionKey key)
=> key.FindAnnotation(RelationalAnnotationNames.Name)?.GetConfigurationSource();

/// <summary>
/// Gets the unique constraints to which the key is mapped.
/// </summary>
/// <param name="key"> The key. </param>
/// <returns> The unique constraints to which the key is mapped. </returns>
public static IEnumerable<IUniqueConstraint> GetMappedConstraints([NotNull] this IKey key) =>
(IEnumerable<IUniqueConstraint>)key[RelationalAnnotationNames.UniqueConstraintMappings]
?? Enumerable.Empty<IUniqueConstraint>();
}
}
10 changes: 10 additions & 0 deletions src/EFCore.Relational/Metadata/ITable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ public interface ITable : ITableBase
/// </summary>
IEnumerable<IForeignKeyConstraint> ForeignKeyConstraints { get; }

/// <summary>
/// Gets the unique constraints for this table.
/// </summary>
IEnumerable<IUniqueConstraint> UniqueConstraints { get; }

/// <summary>
/// Gets the indexes for this table.
/// </summary>
IEnumerable<ITableIndex> Indexes { get; }

/// <summary>
/// Gets the check constraints for this table.
/// </summary>
Expand Down
44 changes: 44 additions & 0 deletions src/EFCore.Relational/Metadata/ITableIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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.Collections.Generic;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Microsoft.EntityFrameworkCore.Metadata
{
/// <summary>
/// Represents a table index.
/// </summary>
public interface ITableIndex : IAnnotatable
{
/// <summary>
/// Gets the name of the index.
/// </summary>
string Name { get; }

/// <summary>
/// Gets the mapped indexes.
/// </summary>
IEnumerable<IIndex> MappedIndexes { get; }

/// <summary>
/// Gets the table on with the index is declared.
/// </summary>
ITable Table { get; }

/// <summary>
/// Gets the columns that are participating in the index.
/// </summary>
IReadOnlyList<IColumn> Columns { get; }

/// <summary>
/// Gets a value indicating whether the index enforces uniqueness.
/// </summary>
bool IsUnique { get; }

/// <summary>
/// Gets the expression used as the index filter.
/// </summary>
string Filter { get; }
}
}
39 changes: 39 additions & 0 deletions src/EFCore.Relational/Metadata/IUniqueConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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.Collections.Generic;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Microsoft.EntityFrameworkCore.Metadata
{
/// <summary>
/// Represents a unique constraint.
/// </summary>
public interface IUniqueConstraint : IAnnotatable
{
/// <summary>
/// Gets the name of the unique constraint.
/// </summary>
string Name { get; }

/// <summary>
/// Gets a value indicating whether this constraint is the primary key.
/// </summary>
bool IsPrimaryKey { get; }

/// <summary>
/// Gets the mapped keys.
/// </summary>
IEnumerable<IKey> MappedKeys { get; }

/// <summary>
/// Gets the table on with the unique constraint is declared.
/// </summary>
ITable Table { get; }

/// <summary>
/// Gets the columns that are participating in the unique constraint.
/// </summary>
IReadOnlyList<IColumn> Columns { get; }
}
}
14 changes: 14 additions & 0 deletions src/EFCore.Relational/Metadata/Internal/Column.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;

Expand Down Expand Up @@ -57,6 +58,19 @@ public Column([NotNull] string name, [CanBeNull] string type, [NotNull] Table ta
/// </summary>
public override string ToString() => this.ToDebugString(MetadataDebugStringOptions.SingleLineDefault);

/// <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 string Format([NotNull] IEnumerable<IColumn> columns)
=> "{"
+ string.Join(
", ",
columns.Select(p => "'" + p.Name + "'"))
+ "}";

/// <inheritdoc/>
IEnumerable<IColumnMapping> IColumn.PropertyMappings
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public ForeignKeyConstraint(
/// 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 SortedSet<IForeignKey> ForeignKeyMappings { get; } = new SortedSet<IForeignKey>(ForeignKeyComparer.Instance);
public virtual SortedSet<IForeignKey> MappedForeignKeys { get; } = new SortedSet<IForeignKey>(ForeignKeyComparer.Instance);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -85,7 +85,7 @@ public ForeignKeyConstraint(
public virtual ReferentialAction OnDeleteAction { get; set; }

/// <inheritdoc />
IEnumerable<IForeignKey> IForeignKeyConstraint.MappedForeignKeys => ForeignKeyMappings;
IEnumerable<IForeignKey> IForeignKeyConstraint.MappedForeignKeys => MappedForeignKeys;

/// <inheritdoc />
ITable IForeignKeyConstraint.Table => Table;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ private ForeignKeyConstraintComparer()
/// </summary>
public int Compare(IForeignKeyConstraint x, IForeignKeyConstraint y)
{
var result = ColumnListComparer.Instance.Compare(x.Columns, y.Columns);
var result = StringComparer.Ordinal.Compare(x.Name, y.Name);
if (result != 0)
{
return result;
}

result = ColumnListComparer.Instance.Compare(x.Columns, y.Columns);
if (result != 0)
{
return result;
Expand Down Expand Up @@ -69,6 +75,7 @@ public bool Equals(IForeignKeyConstraint x, IForeignKeyConstraint y)
public int GetHashCode(IForeignKeyConstraint obj)
{
var hashCode = new HashCode();
hashCode.Add(obj.Name);
hashCode.Add(obj.Columns, ColumnListComparer.Instance);
hashCode.Add(obj.PrincipalColumns, ColumnListComparer.Instance);
hashCode.Add(obj.Table.Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public static string ToDebugString(
.Append(" ")
.Append(foreignKey.Table.Name)
.Append(" ")
.Append(Format(foreignKey.Columns))
.Append(Column.Format(foreignKey.Columns))
.Append(" -> ")
.Append(foreignKey.PrincipalTable.Name)
.Append(" ")
.Append(Format(foreignKey.PrincipalColumns));
.Append(Column.Format(foreignKey.PrincipalColumns));

if (foreignKey.OnDeleteAction != ReferentialAction.NoAction)
{
Expand All @@ -64,12 +64,5 @@ public static string ToDebugString(

return builder.ToString();
}

private static string Format([NotNull] IEnumerable<IColumn> columns)
=> "{"
+ string.Join(
", ",
columns.Select(p => "'" + p.Name + "'"))
+ "}";
}
}
Loading

0 comments on commit afe9774

Please sign in to comment.