Skip to content

Commit

Permalink
Add ForeignKeyConstraint to the relational model.
Browse files Browse the repository at this point in the history
Part of #12846
  • Loading branch information
AndriySvyryd committed Mar 3, 2020
1 parent 725adf7 commit dfbf480
Show file tree
Hide file tree
Showing 23 changed files with 643 additions and 51 deletions.
19 changes: 12 additions & 7 deletions src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
Expand Down Expand Up @@ -164,25 +165,29 @@ public static void SetSchema(
/// Returns the tables to which the entity type is mapped.
/// </summary>
/// <param name="entityType"> The entity type to get the table name for. </param>
/// <returns> The name of the table to which the entity type is mapped. </returns>
/// <returns> The tables to which the entity type is mapped. </returns>
public static IEnumerable<ITableMapping> GetTableMappings([NotNull] this IEntityType entityType) =>
(IEnumerable<ITableMapping>)entityType[RelationalAnnotationNames.TableMappings];
(IEnumerable<ITableMapping>)entityType[RelationalAnnotationNames.TableMappings]
?? Enumerable.Empty<ITableMapping>();

/// <summary>
/// Returns the views or tables to which the entity type is mapped.
/// Returns the views to which the entity type is mapped or the tables of it's not mapped to any views.
/// </summary>
/// <param name="entityType"> The entity type to get the table name for. </param>
/// <returns> The name of the table to which the entity type is mapped. </returns>
/// <returns> The views or tables to which the entity type is mapped. </returns>
public static IEnumerable<ITableMappingBase> GetViewOrTableMappings([NotNull] this IEntityType entityType) =>
(IEnumerable<ITableMappingBase>)GetViewMappings(entityType) ?? GetTableMappings(entityType);
(IEnumerable<ITableMappingBase>)(entityType[RelationalAnnotationNames.ViewMappings]
?? entityType[RelationalAnnotationNames.TableMappings])
?? Enumerable.Empty<ITableMappingBase>();

/// <summary>
/// Returns the views to which the entity type is mapped.
/// </summary>
/// <param name="entityType"> The entity type to get the table name for. </param>
/// <returns> The name of the table to which the entity type is mapped. </returns>
/// <returns> The views to which the entity type is mapped. </returns>
public static IEnumerable<IViewMapping> GetViewMappings([NotNull] this IEntityType entityType) =>
(IEnumerable<IViewMapping>)entityType[RelationalAnnotationNames.ViewMappings];
(IEnumerable<IViewMapping>)entityType[RelationalAnnotationNames.ViewMappings]
?? Enumerable.Empty<IViewMapping>();

/// <summary>
/// Returns the name of the view to which the entity type is mapped.
Expand Down
10 changes: 10 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.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 @@ -75,5 +76,14 @@ public static void SetConstraintName(
public static ConfigurationSource? GetConstraintNameConfigurationSource([NotNull] this IConventionForeignKey foreignKey)
=> foreignKey.FindAnnotation(RelationalAnnotationNames.Name)
?.GetConfigurationSource();

/// <summary>
/// Returns the foreign key constraints to which the foreign key is mapped.
/// </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) =>
(IEnumerable<IForeignKeyConstraint>)foreignKey[RelationalAnnotationNames.ForeignKeyMappings]
?? Enumerable.Empty<IForeignKeyConstraint>();
}
}
4 changes: 2 additions & 2 deletions src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ public static ITable FindTable([NotNull] this IModel model, [NotNull] string nam
/// <summary>
/// Returns all the views mapped in the model.
/// </summary>
/// <param name="model"> The model to get the tables for. </param>
/// <returns> All the tables mapped in the model. </returns>
/// <param name="model"> The model to get the viws for. </param>
/// <returns> All the views mapped in the model. </returns>
public static IEnumerable<IView> GetViews([NotNull] this IModel model) =>
((IDictionary<(string, string), View>)model[RelationalAnnotationNames.Views])?.Values
?? Enumerable.Empty<IView>();
Expand Down
10 changes: 7 additions & 3 deletions src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,23 +278,27 @@ public static void SetColumnType(
/// <param name="property"> The property. </param>
/// <returns> The table columns to which the property is mapped. </returns>
public static IEnumerable<IColumnMapping> GetTableColumnMappings([NotNull] this IProperty property) =>
(IEnumerable<IColumnMapping>)property[RelationalAnnotationNames.TableColumnMappings];
(IEnumerable<IColumnMapping>)property[RelationalAnnotationNames.TableColumnMappings]
?? Enumerable.Empty<IColumnMapping>();

/// <summary>
/// Returns the view or table columns to which the property is mapped.
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> The view or table columns to which the property is mapped. </returns>
public static IEnumerable<IColumnMappingBase> GetViewOrTableColumnMappings([NotNull] this IProperty property) =>
(IEnumerable<IColumnMappingBase>)GetViewColumnMappings(property) ?? GetTableColumnMappings(property);
(IEnumerable<IColumnMappingBase>)(property[RelationalAnnotationNames.ViewColumnMappings]
?? property[RelationalAnnotationNames.TableColumnMappings])
?? Enumerable.Empty<IColumnMappingBase>();

/// <summary>
/// Returns the view columns to which the property is mapped.
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> The view columns to which the property is mapped. </returns>
public static IEnumerable<IViewColumnMapping> GetViewColumnMappings([NotNull] this IProperty property) =>
(IEnumerable<IViewColumnMapping>)property[RelationalAnnotationNames.ViewColumnMappings];
(IEnumerable<IViewColumnMapping>)property[RelationalAnnotationNames.ViewColumnMappings]
?? Enumerable.Empty<IViewColumnMapping>();

/// <summary>
/// Returns the SQL expression that is used as the default value for the column this property is mapped to.
Expand Down
50 changes: 50 additions & 0 deletions src/EFCore.Relational/Metadata/IForeignKeyConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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;
using Microsoft.EntityFrameworkCore.Migrations;

namespace Microsoft.EntityFrameworkCore.Metadata
{
/// <summary>
/// Represents a foreign key constraint.
/// </summary>
public interface IForeignKeyConstraint : IAnnotatable
{
/// <summary>
/// The name of the foreign key constraint.
/// </summary>
string Name { get; }

/// <summary>
/// The mapped foreign keys.
/// </summary>
IEnumerable<IForeignKey> MappedForeignKeys { get; }

/// <summary>
/// The table on with the foreign key constraint is declared.
/// </summary>
ITable Table { get; }

/// <summary>
/// The table that is referenced by the foreign key constraint.
/// </summary>
ITable PrincipalTable { get; }

/// <summary>
/// The columns that are participating in the foreign key constraint.
/// </summary>
IReadOnlyList<IColumn> Columns { get; }

/// <summary>
/// The columns that are referenced by the foreign key constraint.
/// </summary>
IReadOnlyList<IColumn> PrincipalColumns { get; }

/// <summary>
/// The action to be performed when the referenced row is deleted.
/// </summary>
ReferentialAction OnDeleteAction { get; }
}
}
5 changes: 5 additions & 0 deletions src/EFCore.Relational/Metadata/ITable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public interface ITable : ITableBase
/// </summary>
bool IsMigratable { get; }

/// <summary>
/// The foreing key constraints for this table.
/// </summary>
IEnumerable<IForeignKeyConstraint> ForeignKeyConstraints { get; }

/// <summary>
/// The check constraints for this table.
/// </summary>
Expand Down
82 changes: 82 additions & 0 deletions src/EFCore.Relational/Metadata/Internal/ColumnListComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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;
using System.Collections.Generic;

namespace Microsoft.EntityFrameworkCore.Metadata.Internal
{
/// <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>
// Sealed for perf
public sealed class ColumnListComparer : IComparer<IReadOnlyList<IColumn>>, IEqualityComparer<IReadOnlyList<IColumn>>
{
/// <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 readonly ColumnListComparer Instance = new ColumnListComparer();

private ColumnListComparer()
{
}

/// <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 int Compare(IReadOnlyList<IColumn> x, IReadOnlyList<IColumn> y)
{
var result = x.Count - y.Count;

if (result != 0)
{
return result;
}

var index = 0;
while ((result == 0)
&& (index < x.Count))
{
result = StringComparer.Ordinal.Compare(x[index].Name, y[index].Name);
index++;
}

return result;
}

/// <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 bool Equals(IReadOnlyList<IColumn> x, IReadOnlyList<IColumn> y)
=> Compare(x, y) == 0;

/// <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 int GetHashCode(IReadOnlyList<IColumn> obj)
{
var hash = new HashCode();
for (var i = 0; i < obj.Count; i++)
{
hash.Add(obj[i]);
}

return hash.ToHashCode();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal
/// 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 class ColumnMappingComparer : IEqualityComparer<IColumnMapping>, IComparer<IColumnMapping>
public sealed class ColumnMappingComparer : IEqualityComparer<IColumnMapping>, IComparer<IColumnMapping>
{
private ColumnMappingComparer()
{
Expand All @@ -32,7 +32,7 @@ private ColumnMappingComparer()
/// 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 int Compare(IColumnMapping x, IColumnMapping y)
public int Compare(IColumnMapping x, IColumnMapping y)
{
var result = StringComparer.Ordinal.Compare(x.Property.IsColumnNullable(), y.Property.IsColumnNullable());
if (result != 0)
Expand All @@ -55,7 +55,7 @@ public virtual int Compare(IColumnMapping x, IColumnMapping y)
/// 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 Equals(IColumnMapping x, IColumnMapping y)
public bool Equals(IColumnMapping x, IColumnMapping y)
=> x.Property == y.Property
&& x.Column == y.Column;

Expand All @@ -65,7 +65,7 @@ public virtual bool Equals(IColumnMapping x, IColumnMapping y)
/// 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 int GetHashCode(IColumnMapping obj)
public int GetHashCode(IColumnMapping obj)
{
var hashCode = new HashCode();
hashCode.Add(obj.Property.Name);
Expand Down
Loading

0 comments on commit dfbf480

Please sign in to comment.