Skip to content

Commit

Permalink
Add ToFunction overloads that take a MethodInfo
Browse files Browse the repository at this point in the history
Add ToView overloads for owned types
Add non-generic ToInMemoryQuery overloads

Fixes #24611
Fixes #21418
Fixes #24600
  • Loading branch information
AndriySvyryd authored Aug 6, 2021
1 parent 018b50b commit 8460d0f
Show file tree
Hide file tree
Showing 8 changed files with 419 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ namespace Microsoft.EntityFrameworkCore
/// </summary>
public static class InMemoryEntityTypeBuilderExtensions
{
/// <summary>
/// Configures a query used to provide data for an entity type.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param>
/// <param name="query"> The 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 ToInMemoryQuery(
this EntityTypeBuilder entityTypeBuilder,
LambdaExpression? query)
{
Check.NotNull(query, nameof(query));

entityTypeBuilder.Metadata.SetInMemoryQuery(query);

return entityTypeBuilder;
}

/// <summary>
/// Configures a query used to provide data for an entity type.
/// </summary>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ public static IConventionDbFunctionBuilder HasDbFunction(
/// <returns> A builder to further configure the function. </returns>
public static IConventionDbFunctionBuilder HasDbFunction(
this IConventionModelBuilder modelBuilder,
string? name,
string name,
Type returnType,
bool fromDataAnnotation = false)
{
Expand Down
15 changes: 11 additions & 4 deletions src/EFCore.Relational/Metadata/Internal/DbFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public DbFunction(

MethodInfo = methodInfo;

ModelName = GetFunctionName(methodInfo, methodInfo.GetParameters());
ModelName = GetFunctionName(methodInfo);
}

/// <summary>
Expand Down Expand Up @@ -125,8 +125,15 @@ public DbFunction(
}
}

private static string GetFunctionName(MethodInfo methodInfo, ParameterInfo[] parameters)
/// <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 GetFunctionName(MethodInfo methodInfo)
{
var parameters = methodInfo.GetParameters();
var builder = new StringBuilder();

if (methodInfo.DeclaringType != null)
Expand Down Expand Up @@ -201,7 +208,7 @@ public static IEnumerable<IDbFunction> GetDbFunctions(IReadOnlyModel model)
/// </summary>
public static IReadOnlyDbFunction? FindDbFunction(IReadOnlyModel model, MethodInfo methodInfo)
=> model[RelationalAnnotationNames.DbFunctions] is SortedDictionary<string, IDbFunction> functions
&& functions.TryGetValue(GetFunctionName(methodInfo, methodInfo.GetParameters()), out var dbFunction)
&& functions.TryGetValue(GetFunctionName(methodInfo), out var dbFunction)
? dbFunction
: null;

Expand Down Expand Up @@ -268,7 +275,7 @@ private static SortedDictionary<string, IDbFunction> GetOrCreateFunctions(IMutab
{
if (model[RelationalAnnotationNames.DbFunctions] is SortedDictionary<string, IDbFunction> functions)
{
var name = GetFunctionName(methodInfo, methodInfo.GetParameters());
var name = GetFunctionName(methodInfo);
if (functions.TryGetValue(name, out var function))
{
var dbFunction = (DbFunction)function;
Expand Down
81 changes: 81 additions & 0 deletions test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2481,6 +2481,87 @@ public virtual void Shared_owned_types_are_stored_in_snapshot()
});
}

[ConditionalFact]
public virtual void Owned_types_can_be_mapped_to_view()
{
Test(
modelBuilder =>
{
modelBuilder.Entity<TestOwner>()
.OwnsMany(
o => o.OwnedEntities,
ownee => ownee.ToView("OwnedView"));
},
@"// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace RootNamespace
{
[DbContext(typeof(DbContext))]
partial class Snapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation(""Relational:MaxIdentifierLength"", 128)
.HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwner"", b =>
{
b.Property<int>(""Id"")
.ValueGeneratedOnAdd()
.HasColumnType(""int"")
.HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);
b.HasKey(""Id"");
b.ToTable(""TestOwner"");
});
modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwner"", b =>
{
b.OwnsMany(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwnee"", ""OwnedEntities"", b1 =>
{
b1.Property<int>(""TestOwnerId"")
.HasColumnType(""int"");
b1.Property<int>(""Id"")
.HasColumnType(""int"")
.HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);
b1.Property<int>(""TestEnum"")
.HasColumnType(""int"");
b1.HasKey(""TestOwnerId"", ""Id"");
b1.ToView(""OwnedView"");
b1.WithOwner()
.HasForeignKey(""TestOwnerId"");
});
b.Navigation(""OwnedEntities"");
});
#pragma warning restore 612, 618
}
}
}
",
model =>
{
Assert.Equal(2, model.GetEntityTypes().Count());
var testOwner = model.FindEntityType(
"Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwner");
var testOwnee = model.FindEntityType(
"Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwnee", "OwnedEntities", testOwner);
Assert.Equal("OwnedView", testOwnee.GetViewName());
});
}

[ConditionalFact]
public virtual void Snapshot_with_OwnedNavigationBuilder_HasCheckConstraint_compiles()
{
Expand Down
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.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Xunit;
Expand All @@ -15,7 +16,9 @@ public virtual void Detects_ToQuery_on_derived_keyless_types()
var modelBuilder = base.CreateConventionalModelBuilder();
var context = new DbContext(new DbContextOptions<DbContext>());
modelBuilder.Entity<Abstract>().HasNoKey().ToInMemoryQuery(() => context.Set<Abstract>());
modelBuilder.Entity<Generic<int>>().ToInMemoryQuery(() => context.Set<Generic<int>>());

Expression<Func<IQueryable<Generic<int>>>> query = () => context.Set<Generic<int>>();
modelBuilder.Entity<Generic<int>>().ToInMemoryQuery((LambdaExpression)query);

VerifyError(
CoreStrings.DerivedTypeDefiningQuery("Generic<int>", nameof(Abstract)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1830,9 +1830,7 @@ public void Detects_entity_type_mapped_to_a_different_type()
{
var modelBuilder = CreateConventionalModelBuilder();

var function = modelBuilder.HasDbFunction(TestMethods.MethodAMi).Metadata;

modelBuilder.Entity<Animal>().HasNoKey().ToFunction(function.ModelName);
modelBuilder.Entity<Animal>().HasNoKey().ToFunction(TestMethods.MethodAMi);
modelBuilder.Entity<TestMethods>().HasNoKey();

VerifyError(
Expand All @@ -1849,9 +1847,8 @@ public void Detects_entity_type_mapped_to_a_function_with_parameters()
{
var modelBuilder = CreateConventionalModelBuilder();

var function = modelBuilder.HasDbFunction(TestMethods.MethodBMi).Metadata;

modelBuilder.Entity<TestMethods>().HasNoKey().ToFunction(function.ModelName);
((IConventionEntityType)modelBuilder.Entity<TestMethods>().HasNoKey().Metadata)
.Builder.ToFunction(TestMethods.MethodBMi);

VerifyError(
RelationalStrings.InvalidMappedFunctionWithParameters(
Expand Down
6 changes: 6 additions & 0 deletions test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ public override
typeof(IMutableSequence).GetMethod("set_ClrType"),
typeof(RelationalEntityTypeBuilderExtensions).GetMethod(
nameof(RelationalEntityTypeBuilderExtensions.ExcludeTableFromMigrations)),
typeof(RelationalEntityTypeBuilderExtensions).GetMethod(
nameof(RelationalEntityTypeBuilderExtensions.CanSetFunction),
new Type[] { typeof(IConventionEntityTypeBuilder), typeof(MethodInfo), typeof(bool) }),
typeof(RelationalEntityTypeBuilderExtensions).GetMethod(
nameof(RelationalEntityTypeBuilderExtensions.ToFunction),
new Type[] { typeof(IConventionEntityTypeBuilder), typeof(string), typeof(bool) }),
typeof(RelationalEntityTypeBuilderExtensions).GetMethod(
nameof(RelationalEntityTypeBuilderExtensions.ToTable),
new Type[] { typeof(EntityTypeBuilder), typeof(Action<TableBuilder>) }),
Expand Down

0 comments on commit 8460d0f

Please sign in to comment.