Skip to content

Commit

Permalink
[release/9.0] Use the correct comparer when sorting relational functi…
Browse files Browse the repository at this point in the history
…ons. (#34712)

Fixes #34672
  • Loading branch information
AndriySvyryd authored Sep 19, 2024
1 parent 726ce85 commit 59d16b6
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2068,7 +2068,7 @@ IEnumerable<IView> IRelationalModel.Views
IEnumerable<IStoreFunction> IRelationalModel.Functions
{
[DebuggerStepThrough]
get => Functions.OrderBy(f => f.Key).Select(t => t.Value);
get => Functions.OrderBy(f => f.Key, NamedListComparer.Instance).Select(t => t.Value);
}

IEnumerable<IStoreStoredProcedure> IRelationalModel.StoredProcedures
Expand Down
47 changes: 37 additions & 10 deletions test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3046,6 +3046,9 @@ public void Can_use_relational_model_with_SQL_queries()
private static IQueryable<Order> GetOrdersForCustomer(int id)
=> throw new NotImplementedException();

private static IQueryable<Order> GetOrdersForCustomer(string name)
=> throw new NotImplementedException();

[ConditionalFact]
public void Can_use_relational_model_with_functions()
{
Expand All @@ -3064,41 +3067,50 @@ public void Can_use_relational_model_with_functions()

modelBuilder.HasDbFunction(
typeof(RelationalModelTest).GetMethod(
nameof(GetOrdersForCustomer), BindingFlags.NonPublic | BindingFlags.Static));
nameof(GetOrdersForCustomer), BindingFlags.NonPublic | BindingFlags.Static, [typeof(int)] ));

modelBuilder.HasDbFunction(
typeof(RelationalModelTest).GetMethod(
nameof(GetOrdersForCustomer), BindingFlags.NonPublic | BindingFlags.Static, [typeof(string)]));

var model = Finalize(modelBuilder);

Assert.Single(model.Model.GetEntityTypes());
Assert.Equal(2, model.Functions.Count());
Assert.Equal(3, model.Functions.Count());
Assert.Empty(model.Views);
Assert.Empty(model.Tables);

var orderType = model.Model.FindEntityType(typeof(Order));
Assert.Null(orderType.FindPrimaryKey());

Assert.Equal(2, orderType.GetFunctionMappings().Count());
Assert.Equal(3, orderType.GetFunctionMappings().Count());
var orderMapping = orderType.GetFunctionMappings().First();
Assert.Null(orderMapping.IsSharedTablePrincipal);
Assert.Null(orderMapping.IsSplitEntityTypePrincipal);
Assert.True(orderMapping.IsDefaultFunctionMapping);

var tvfMapping = orderType.GetFunctionMappings().Last();
var tvfMapping = orderType.GetFunctionMappings().ElementAt(1);
Assert.Null(tvfMapping.IsSharedTablePrincipal);
Assert.Null(tvfMapping.IsSplitEntityTypePrincipal);
Assert.False(tvfMapping.IsDefaultFunctionMapping);

var tvfMapping2 = orderType.GetFunctionMappings().Last();
Assert.Null(tvfMapping2.IsSharedTablePrincipal);
Assert.Null(tvfMapping2.IsSplitEntityTypePrincipal);
Assert.False(tvfMapping2.IsDefaultFunctionMapping);

Assert.Null(orderMapping.IncludesDerivedTypes);
Assert.Equal(
new[] { nameof(Order.AlternateId), nameof(Order.CustomerId), nameof(Order.Id), nameof(Order.OrderDate) },
[nameof(Order.AlternateId), nameof(Order.CustomerId), nameof(Order.Id), nameof(Order.OrderDate)],
orderMapping.ColumnMappings.Select(m => m.Property.Name));

var ordersFunction = orderMapping.StoreFunction;
Assert.Same(ordersFunction, model.FindFunction(ordersFunction.Name, ordersFunction.Schema, []));
Assert.Equal(
new[] { orderType },
[orderType],
ordersFunction.EntityTypeMappings.Select(m => m.TypeBase));
Assert.Equal(
new[] { nameof(Order.CustomerId), nameof(Order.Id), nameof(Order.OrderDate), "SomeName" },
[nameof(Order.CustomerId), nameof(Order.Id), nameof(Order.OrderDate), "SomeName"],
ordersFunction.Columns.Select(m => m.Name));
Assert.Equal("GetOrders", ordersFunction.Name);
Assert.Null(ordersFunction.Schema);
Expand All @@ -3117,7 +3129,7 @@ public void Can_use_relational_model_with_functions()
Assert.Same(orderDateColumn, ordersFunction.FindColumn(nameof(Order.OrderDate)));
Assert.Same(orderDateColumn, orderDate.FindColumn(StoreObjectIdentifier.DbFunction(ordersFunction.Name)));
Assert.Same(orderDateColumn, ordersFunction.FindColumn(orderDate));
Assert.Equal(new[] { orderDate }, orderDateColumn.PropertyMappings.Select(m => m.Property));
Assert.Equal([orderDate], orderDateColumn.PropertyMappings.Select(m => m.Property));
Assert.Equal(nameof(Order.OrderDate), orderDateColumn.Name);
Assert.Equal("default_datetime_mapping", orderDateColumn.StoreType);
Assert.False(orderDateColumn.IsNullable);
Expand All @@ -3127,7 +3139,7 @@ public void Can_use_relational_model_with_functions()

var tvfFunction = tvfMapping.StoreFunction;
Assert.Same(tvfMapping, tvfFunction.EntityTypeMappings.Single());
Assert.Same(tvfFunction, model.FindFunction(tvfFunction.Name, tvfFunction.Schema, new[] { "default_int_mapping" }));
Assert.Same(tvfFunction, model.FindFunction(tvfFunction.Name, tvfFunction.Schema, ["default_int_mapping"]));
Assert.Equal(nameof(GetOrdersForCustomer), tvfFunction.Name);
Assert.Null(tvfFunction.Schema);
Assert.False(tvfFunction.IsBuiltIn);
Expand All @@ -3136,9 +3148,24 @@ public void Can_use_relational_model_with_functions()

var tvfDbFunction = tvfFunction.DbFunctions.Single();
Assert.Same(tvfFunction, tvfDbFunction.StoreFunction);
Assert.Same(model.Model.GetDbFunctions().Single(f => f.Parameters.Count() == 1), tvfDbFunction);
Assert.Same(model.Model.GetDbFunctions().First(f => f.Parameters.Count() == 1), tvfDbFunction);
Assert.Same(tvfFunction.Parameters.Single(), tvfDbFunction.Parameters.Single().StoreFunctionParameter);
Assert.Equal(tvfDbFunction.Parameters.Single().Name, tvfFunction.Parameters.Single().DbFunctionParameters.Single().Name);

var tvfFunction2 = tvfMapping2.StoreFunction;
Assert.Same(tvfMapping2, tvfFunction2.EntityTypeMappings.Single());
Assert.Same(tvfFunction2, model.FindFunction(tvfFunction2.Name, tvfFunction2.Schema, ["just_string(max)"]));
Assert.Equal(nameof(GetOrdersForCustomer), tvfFunction2.Name);
Assert.Null(tvfFunction2.Schema);
Assert.False(tvfFunction2.IsBuiltIn);
Assert.False(tvfFunction2.IsShared);
Assert.Null(tvfFunction2.ReturnType);

var tvfDbFunction2 = tvfFunction2.DbFunctions.Single();
Assert.Same(tvfFunction2, tvfDbFunction2.StoreFunction);
Assert.Same(model.Model.GetDbFunctions().Last(f => f.Parameters.Count() == 1), tvfDbFunction2);
Assert.Same(tvfFunction2.Parameters.Single(), tvfDbFunction2.Parameters.Single().StoreFunctionParameter);
Assert.Equal(tvfDbFunction2.Parameters.Single().Name, tvfFunction2.Parameters.Single().DbFunctionParameters.Single().Name);
}

[ConditionalFact]
Expand Down

0 comments on commit 59d16b6

Please sign in to comment.