Skip to content

Commit

Permalink
Allow mapping entity types to SQL queries
Browse files Browse the repository at this point in the history
Fixes #13358
Part of #17063
  • Loading branch information
AndriySvyryd authored Jul 20, 2020
1 parent ffcb62d commit 13e69ca
Show file tree
Hide file tree
Showing 72 changed files with 1,914 additions and 682 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static EntityTypeBuilder<TEntity> ToQuery<TEntity>(
/// <returns>
/// The same builder instance if the query was set, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder HasDefiningQuery(
public static IConventionEntityTypeBuilder ToQuery(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
[CanBeNull] LambdaExpression query,
bool fromDataAnnotation = false)
Expand Down
5 changes: 4 additions & 1 deletion src/EFCore.Relational/Design/AnnotationCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ public class AnnotationCodeGenerator : IAnnotationCodeGenerator
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.DbFunctions,
RelationalAnnotationNames.DefaultMappings,
RelationalAnnotationNames.DefaultColumnMappings,
RelationalAnnotationNames.TableMappings,
RelationalAnnotationNames.TableColumnMappings,
RelationalAnnotationNames.ViewMappings,
RelationalAnnotationNames.ViewColumnMappings,
RelationalAnnotationNames.FunctionMappings,
RelationalAnnotationNames.FunctionColumnMappings,
RelationalAnnotationNames.SqlQueryMappings,
RelationalAnnotationNames.SqlQueryColumnMappings,
RelationalAnnotationNames.ForeignKeyMappings,
RelationalAnnotationNames.TableIndexMappings,
RelationalAnnotationNames.UniqueConstraintMappings,
Expand Down Expand Up @@ -83,7 +87,6 @@ public virtual void RemoveAnnotationsHandledByConventions(
IProperty property, IDictionary<string, IAnnotation> annotations)
{
var columnName = property.GetColumnName();

if (columnName == property.Name)
{
annotations.Remove(RelationalAnnotationNames.ColumnName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
Expand Down Expand Up @@ -282,8 +281,7 @@ public static OwnedNavigationBuilder<TEntity, TRelatedEntity> ToTable<TEntity, T
/// <param name="name"> The name of the table. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied,
/// <see langword="null" /> otherwise.
/// The same builder instance if the configuration was applied, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder ToTable(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder, [CanBeNull] string name, bool fromDataAnnotation = false)
Expand All @@ -305,8 +303,7 @@ public static IConventionEntityTypeBuilder ToTable(
/// <param name="schema"> The schema of the table. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied,
/// <see langword="null" /> otherwise.
/// The same builder instance if the configuration was applied, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder ToTable(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
Expand All @@ -325,11 +322,11 @@ public static IConventionEntityTypeBuilder ToTable(
}

/// <summary>
/// Returns a value indicating whether the view or table name can be set for this entity type
/// Returns a value indicating whether the table name can be set for this entity type
/// using the specified configuration source.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="name"> The name of the view or table. </param>
/// <param name="name"> The name of the table. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <see langword="true" /> if the configuration can be applied. </returns>
public static bool CanSetTable(
Expand All @@ -341,14 +338,13 @@ public static bool CanSetTable(
}

/// <summary>
/// Configures the schema of the view or table that the entity type maps to when targeting a relational database.
/// Configures the schema of the table that the entity type maps to when targeting a relational database.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="schema"> The schema of the view or table. </param>
/// <param name="schema"> The schema of the table. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied,
/// <see langword="null" /> otherwise.
/// The same builder instance if the configuration was applied, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder ToSchema(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
Expand All @@ -365,11 +361,11 @@ public static IConventionEntityTypeBuilder ToSchema(
}

/// <summary>
/// Returns a value indicating whether the schema of the view or table name can be set for this entity type
/// Returns a value indicating whether the schema of the table name can be set for this entity type
/// using the specified configuration source.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="schema"> The schema of the view or table. </param>
/// <param name="schema"> The schema of the table. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <see langword="true" /> if the configuration can be applied. </returns>
public static bool CanSetSchema(
Expand Down Expand Up @@ -481,6 +477,167 @@ public static EntityTypeBuilder<TEntity> ToView<TEntity>(
where TEntity : class
=> (EntityTypeBuilder<TEntity>)ToView((EntityTypeBuilder)entityTypeBuilder, name, schema);

/// <summary>
/// Configures the view that the entity type maps to when targeting a relational database.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="name"> The name of the view. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder ToView(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder, [CanBeNull] string name, bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanSetView(name, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.SetViewName(name, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Configures the view that the entity type maps to when targeting a relational database.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="name"> The name of the view. </param>
/// <param name="schema"> The schema of the view. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder ToView(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
[CanBeNull] string name, [CanBeNull] string schema,
bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanSetView(name, fromDataAnnotation)
|| !entityTypeBuilder.CanSetViewSchema(schema, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.SetViewName(name, fromDataAnnotation);
entityTypeBuilder.Metadata.SetViewSchema(schema, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether the view name can be set for this entity type
/// using the specified configuration source.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="name"> The name of the view. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <see langword="true" /> if the configuration can be applied. </returns>
public static bool CanSetView(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder, [CanBeNull] string name, bool fromDataAnnotation = false)
{
Check.NullButNotEmpty(name, nameof(name));

return entityTypeBuilder.CanSetAnnotation(RelationalAnnotationNames.ViewName, name, fromDataAnnotation);
}

/// <summary>
/// Configures the schema of the view that the entity type maps to when targeting a relational database.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="schema"> The schema of the view. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder ToViewSchema(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
[CanBeNull] string schema,
bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanSetSchema(schema, fromDataAnnotation))
{
return null;
}

entityTypeBuilder.Metadata.SetViewSchema(schema, fromDataAnnotation);
return entityTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether the schema of the view can be set for this entity type
/// using the specified configuration source.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="schema"> The schema of the view. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <see langword="true" /> if the configuration can be applied. </returns>
public static bool CanSetViewSchema(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder,
[CanBeNull] string schema,
bool fromDataAnnotation = false)
{
Check.NullButNotEmpty(schema, nameof(schema));

return entityTypeBuilder.CanSetAnnotation(RelationalAnnotationNames.ViewSchema, schema, fromDataAnnotation);
}

/// <summary>
/// Configures a SQL string used to provide data for the entity type.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="query"> The SQL query that will provide the underlying data for the entity type. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
public static EntityTypeBuilder<TEntity> ToQuerySql<TEntity>(
[NotNull] this EntityTypeBuilder<TEntity> entityTypeBuilder,
[NotNull] string query)
where TEntity : class
{
Check.NotNull(query, nameof(query));

entityTypeBuilder.Metadata.SetQuerySql(query);

return entityTypeBuilder;
}

/// <summary>
/// Configures a SQL string used to provide data for the entity type.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="name"> The SQL query that will provide the underlying data for the entity type. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns>
/// The same builder instance if the configuration was applied, <see langword="null" /> otherwise.
/// </returns>
public static IConventionEntityTypeBuilder ToQuerySql(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder, [CanBeNull] string name, bool fromDataAnnotation = false)
{
if (!entityTypeBuilder.CanSetQuerySql(name, fromDataAnnotation))
{
return null;
}

var entityType = entityTypeBuilder.Metadata;
entityType.SetQuerySql(name, fromDataAnnotation);

return entityTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether the query SQL string can be set for this entity type
/// using the specified configuration source.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="name"> The SQL query that will provide the underlying data for the entity type. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> <see langword="true" /> if the configuration can be applied. </returns>
public static bool CanSetQuerySql(
[NotNull] this IConventionEntityTypeBuilder entityTypeBuilder, [CanBeNull] string name, bool fromDataAnnotation = false)
{
Check.NullButNotEmpty(name, nameof(name));

return entityTypeBuilder.CanSetAnnotation(RelationalAnnotationNames.QuerySql, name, fromDataAnnotation);
}

/// <summary>
/// Configures the function that the entity type maps to when targeting a relational database.
/// </summary>
Expand Down
Loading

0 comments on commit 13e69ca

Please sign in to comment.