Skip to content

Commit

Permalink
Add view support to the relational model API
Browse files Browse the repository at this point in the history
Use the new model in the query pipeline

Fixes #12846
  • Loading branch information
AndriySvyryd committed Feb 19, 2020
1 parent 1a73b7e commit 9cce8fc
Show file tree
Hide file tree
Showing 37 changed files with 1,431 additions and 253 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ public virtual void Generate(string builderName, IModel model, IndentedStringBui
CoreAnnotationNames.ChangeTrackingStrategy,
CoreAnnotationNames.OwnedTypes,
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Tables);
RelationalAnnotationNames.Tables,
RelationalAnnotationNames.Views);

if (annotations.Count > 0)
{
Expand Down Expand Up @@ -497,6 +498,7 @@ protected virtual void GeneratePropertyAnnotations([NotNull] IProperty property,
annotations,
RelationalAnnotationNames.ColumnType,
RelationalAnnotationNames.TableColumnMappings,
RelationalAnnotationNames.ViewColumnMappings,
CoreAnnotationNames.ValueGeneratorFactory,
CoreAnnotationNames.PropertyAccessMode,
CoreAnnotationNames.ChangeTrackingStrategy,
Expand Down Expand Up @@ -787,7 +789,8 @@ protected virtual void GenerateEntityTypeAnnotations(
CoreAnnotationNames.DefiningQuery,
CoreAnnotationNames.QueryFilter,
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.TableMappings);
RelationalAnnotationNames.TableMappings,
RelationalAnnotationNames.ViewMappings);

if (annotations.Count > 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,10 @@ private IEnumerable<string> GetAnnotationNamespaces(IEnumerable<IAnnotatable> it
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Tables,
RelationalAnnotationNames.TableMappings,
RelationalAnnotationNames.TableColumnMappings
RelationalAnnotationNames.TableColumnMappings,
RelationalAnnotationNames.Views,
RelationalAnnotationNames.ViewMappings,
RelationalAnnotationNames.ViewColumnMappings
};

var ignoredAnnotationTypes = new List<string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ protected virtual void GenerateOnModelCreating(
RemoveAnnotation(ref annotations, RelationalAnnotationNames.MaxIdentifierLength);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.CheckConstraints);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Tables);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Views);
RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.DatabaseName);
RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.EntityTypeErrors);

Expand Down Expand Up @@ -366,6 +367,7 @@ private void GenerateEntityType(IEntityType entityType, bool useDataAnnotations)
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Comment);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.Schema);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.TableMappings);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.ViewMappings);
RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.DbSetName);

RemoveAnnotation(ref annotations, RelationalAnnotationNames.ViewDefinition);
Expand Down Expand Up @@ -616,6 +618,7 @@ private void GenerateProperty(IProperty property, bool useDataAnnotations)
RemoveAnnotation(ref annotations, RelationalAnnotationNames.ComputedColumnSql);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.IsFixedLength);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.TableColumnMappings);
RemoveAnnotation(ref annotations, RelationalAnnotationNames.ViewColumnMappings);
RemoveAnnotation(ref annotations, ScaffoldingAnnotationNames.ColumnOrdinal);

if (!useDataAnnotations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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 JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
Expand Down Expand Up @@ -146,13 +147,29 @@ public static void SetSchema(
?.GetConfigurationSource();

/// <summary>
/// Returns the name of the table to which the entity type is mapped.
/// 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>
public static IEnumerable<ITableMapping> GetTableMappings([NotNull] this IEntityType entityType) =>
(IEnumerable<ITableMapping>)entityType[RelationalAnnotationNames.TableMappings];

/// <summary>
/// Returns the views or 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>
public static IEnumerable<ITableMappingBase> GetViewOrTableMappings([NotNull] this IEntityType entityType) =>
(IEnumerable<ITableMappingBase>)GetViewMappings(entityType) ?? GetTableMappings(entityType);

/// <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>
public static IEnumerable<IViewMapping> GetViewMappings([NotNull] this IEntityType entityType) =>
(IEnumerable<IViewMapping>)entityType[RelationalAnnotationNames.ViewMappings];

/// <summary>
/// Returns the name of the view to which the entity type is mapped.
/// </summary>
Expand Down
36 changes: 33 additions & 3 deletions src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public static void SetDefaultSchema(
/// <param name="model"> The model to get the tables for. </param>
/// <returns> All the tables mapped in the model. </returns>
public static IEnumerable<ITable> GetTables([NotNull] this IModel model) =>
((IDictionary<(string, string), Table>)model[RelationalAnnotationNames.Tables]).Values;
((IDictionary<(string, string), Table>)model[RelationalAnnotationNames.Tables])?.Values
?? Enumerable.Empty<ITable>();

/// <summary>
/// Gets the table with a given name. Returns <c>null</c> if no table with the given name is defined.
Expand All @@ -70,10 +71,39 @@ public static IEnumerable<ITable> GetTables([NotNull] this IModel model) =>
/// <param name="name"> The name of the table. </param>
/// <param name="schema"> The schema of the table. </param>
/// <returns> The table with a given name or <c>null</c> if no table with the given name is defined. </returns>
public static ITable FindTable([NotNull] this IModel model, [NotNull] string name, [CanBeNull] string schema) =>
((IDictionary<(string, string), Table>)model[RelationalAnnotationNames.Tables]).TryGetValue((name, schema), out var table)
public static ITable FindTable([NotNull] this IModel model, [NotNull] string name, [CanBeNull] string schema)
{
Table table = null;
return ((IDictionary<(string, string), Table>)model[RelationalAnnotationNames.Tables])
?.TryGetValue((name, schema), out table) == true
? table
: null;
}

/// <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>
public static IEnumerable<IView> GetViews([NotNull] this IModel model) =>
((IDictionary<(string, string), View>)model[RelationalAnnotationNames.Views])?.Values
?? Enumerable.Empty<IView>();

/// <summary>
/// Gets the view with a given name. Returns <c>null</c> if no view with the given name is defined.
/// </summary>
/// <param name="model"> The model to get the view for. </param>
/// <param name="name"> The name of the view. </param>
/// <param name="schema"> The schema of the view. </param>
/// <returns> The view with a given name or <c>null</c> if no view with the given name is defined. </returns>
public static IView FindView([NotNull] this IModel model, [NotNull] string name, [CanBeNull] string schema)
{
View view = null;
return ((IDictionary<(string, string), View>)model[RelationalAnnotationNames.Views])
?.TryGetValue((name, schema), out view) == true
? view
: null;
}

/// <summary>
/// Returns the maximum length allowed for store identifiers.
Expand Down
20 changes: 18 additions & 2 deletions src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,29 @@ public static void SetColumnType(
=> property.FindAnnotation(RelationalAnnotationNames.ColumnType)?.GetConfigurationSource();

/// <summary>
/// Returns the columns to which the property is mapped.
/// Returns the table columns to which the property is mapped.
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> The name of the table to which the entity type is mapped. </returns>
/// <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];

/// <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);

/// <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];

/// <summary>
/// Returns the SQL expression that is used as the default value for the column this property is mapped to.
/// </summary>
Expand Down
33 changes: 9 additions & 24 deletions src/EFCore.Relational/Metadata/ITable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,21 @@ public interface ITable : ITableBase
bool IsMigratable { get; }

/// <summary>
/// Returns a value indicating whether multiple entity types are sharing the rows in the table.
/// The check constraints for this table.
/// </summary>
bool IsSplit { get; }

/// <summary>
/// Returns the column with a given name. Returns <c>null</c> if no column with the given name is defined.
/// </summary>
IColumn FindColumn([NotNull] string name);

/// <summary>
/// Returns the foreign keys for the given entity type that point to other entity types sharing this table.
/// </summary>
IEnumerable<IForeignKey> GetInternalForeignKeys([NotNull] IEntityType entityType);

/// <summary>
/// Returns the foreign keys referencing the given entity type from other entity types sharing this table.
/// </summary>
IEnumerable<IForeignKey> GetReferencingInternalForeignKeys([NotNull] IEntityType entityType);

/// <summary>
/// Returns the check constraints for this table.
/// </summary>
IEnumerable<ICheckConstraint> GetCheckConstraints()
IEnumerable<ICheckConstraint> CheckConstraints
=> EntityTypeMappings.SelectMany(m => CheckConstraint.GetCheckConstraints(m.EntityType))
.Distinct((x, y) => x.Name == y.Name);

/// <summary>
/// Returns the comment for this table.
/// The comment for this table.
/// </summary>
public virtual string GetComment()
public virtual string Comment
=> EntityTypeMappings.Select(e => e.EntityType.GetComment()).FirstOrDefault(c => c != null);

/// <summary>
/// Returns the column with a given name. Returns <c>null</c> if no column with the given name is defined.
/// </summary>
new IColumn FindColumn([NotNull] string name);
}
}
21 changes: 21 additions & 0 deletions src/EFCore.Relational/Metadata/ITableBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Microsoft.EntityFrameworkCore.Metadata
Expand All @@ -21,6 +22,11 @@ public interface ITableBase : IAnnotatable
/// </summary>
string Schema { get; }

/// <summary>
/// Returns a value indicating whether multiple entity types are sharing the rows in the table.
/// </summary>
bool IsSplit { get; }

/// <summary>
/// The entity type mappings.
/// </summary>
Expand All @@ -30,5 +36,20 @@ public interface ITableBase : IAnnotatable
/// The columns defined for this table.
/// </summary>
IEnumerable<IColumnBase> Columns { get; }

/// <summary>
/// Returns the column with a given name. Returns <c>null</c> if no column with the given name is defined.
/// </summary>
IColumnBase FindColumn([NotNull] string name);

/// <summary>
/// Returns the foreign keys for the given entity type that point to other entity types sharing this table.
/// </summary>
IEnumerable<IForeignKey> GetInternalForeignKeys([NotNull] IEntityType entityType);

/// <summary>
/// Returns the foreign keys referencing the given entity type from other entity types sharing this table.
/// </summary>
IEnumerable<IForeignKey> GetReferencingInternalForeignKeys([NotNull] IEntityType entityType);
}
}
34 changes: 34 additions & 0 deletions src/EFCore.Relational/Metadata/IView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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 JetBrains.Annotations;

namespace Microsoft.EntityFrameworkCore.Metadata
{
/// <summary>
/// Represents a view in the database.
/// </summary>
public interface IView : ITableBase
{
/// <summary>
/// The entity type mappings.
/// </summary>
new IEnumerable<IViewMapping> EntityTypeMappings { get; }

/// <summary>
/// The columns defined for this view.
/// </summary>
new IEnumerable<IViewColumn> Columns { get; }

/// <summary>
/// Returns the column with a given name. Returns <c>null</c> if no column with the given name is defined.
/// </summary>
new IViewColumn FindColumn([NotNull] string name);

/// <summary>
/// The view definition or <c>null</c> if this view is not managed by migrations.
/// </summary>
public string ViewDefinition { get; }
}
}
23 changes: 23 additions & 0 deletions src/EFCore.Relational/Metadata/IViewColumn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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;

namespace Microsoft.EntityFrameworkCore.Metadata
{
/// <summary>
/// Represents a column in a view.
/// </summary>
public interface IViewColumn : IColumnBase
{
/// <summary>
/// The containing view.
/// </summary>
IView View { get; }

/// <summary>
/// The property mappings.
/// </summary>
new IEnumerable<IViewColumnMapping> PropertyMappings { get; }
}
}
21 changes: 21 additions & 0 deletions src/EFCore.Relational/Metadata/IViewColumnMapping.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.

namespace Microsoft.EntityFrameworkCore.Metadata
{
/// <summary>
/// Represents property mapping to a column.
/// </summary>
public interface IViewColumnMapping : IColumnMappingBase
{
/// <summary>
/// The target column.
/// </summary>
new IViewColumn Column { get; }

/// <summary>
/// The containing view mapping.
/// </summary>
IViewMapping ViewMapping { get; }
}
}
23 changes: 23 additions & 0 deletions src/EFCore.Relational/Metadata/IViewMapping.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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;

namespace Microsoft.EntityFrameworkCore.Metadata
{
/// <summary>
/// Represents entity type mapping to a view.
/// </summary>
public interface IViewMapping : ITableMappingBase
{
/// <summary>
/// The target view.
/// </summary>
IView View { get; }

/// <summary>
/// The properties mapped to columns on the target view.
/// </summary>
new IEnumerable<IViewColumnMapping> ColumnMappings { get; }
}
}
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/Internal/Column.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class Column : Annotatable, IColumn
/// 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 Column([NotNull] string name, [NotNull] string type, [NotNull] ITable table)
public Column([NotNull] string name, [NotNull] string type, [NotNull] Table table)
{
Name = name;
Type = type;
Expand Down
4 changes: 2 additions & 2 deletions src/EFCore.Relational/Metadata/Internal/ColumnMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public class ColumnMapping : Annotatable, IColumnMapping
/// </summary>
public ColumnMapping(
[NotNull] IProperty property,
[NotNull] IColumn column,
[NotNull] Column column,
[NotNull] RelationalTypeMapping typeMapping,
[NotNull] ITableMapping tableMapping)
[NotNull] TableMapping tableMapping)
{
Property = property;
Column = column;
Expand Down
Loading

0 comments on commit 9cce8fc

Please sign in to comment.