Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix orderby with PageSize on derived types #980

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1205,8 +1205,10 @@ private Expression ProjectCollection(QueryBinderContext context, Expression sour
bool alreadyOrdered = false;
foreach (var prop in properties)
{
source = ExpressionHelpers.OrderByPropertyExpression(source, prop.Name, elementType,
string propertyName = context.Model.GetClrPropertyName(prop);
source = ExpressionHelpers.OrderByPropertyExpression(source, propertyName, elementType,
alreadyOrdered);

if (!alreadyOrdered)
{
alreadyOrdered = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Xml.Linq;
using Microsoft.AspNetCore.OData.Edm;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Query.Container;
Expand Down Expand Up @@ -40,16 +42,20 @@ public class SelectExpandBinderTest
private readonly IEdmModel _model;
private readonly IEdmEntityType _customer;
private readonly IEdmEntityType _order;
private readonly IEdmEntityType _product;
private readonly IEdmEntitySet _customers;
private readonly IEdmEntitySet _orders;
private readonly IEdmEntitySet _products;

public SelectExpandBinderTest()
{
_model = GetEdmModel();
_customer = _model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "QueryCustomer");
_order = _model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "QueryOrder");
_product = _model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "QueryProduct");
_customers = _model.EntityContainer.FindEntitySet("Customers");
_orders = _model.EntityContainer.FindEntitySet("Orders");
_products = _model.EntityContainer.FindEntitySet("Products");

_settings = new ODataQuerySettings { HandleNullPropagation = HandleNullPropagationOption.False };
_context = new ODataQueryContext(_model, typeof(QueryCustomer)) { RequestContainer = new MockServiceProvider() };
Expand Down Expand Up @@ -109,6 +115,73 @@ public void Bind_ReturnsIEdmObject_WithRightEdmType(string select)
Assert.Same(_customer, edmType.AsElementType());
}

[Theory]
[InlineData("ProductTags")]
[InlineData("ProductTags($orderby=$this/Name)")]
[InlineData("ProductTags($orderby=$this/Name desc)")]
public void Bind_SelectAndOrderBy_PropertyFromDataMember(string expand)
{
// Arrange
IQueryable<QueryProduct> products;

QueryProduct product1 = new QueryProduct
{
Id = 1,
Name = "Product 1",
Quantity = 1,
Tags = new List<QueryProductTag>()
{
new QueryProductTag(){Id = 1001, Name = "Tag 1" },
new QueryProductTag(){Id = 1002, Name = "Tag 2" },
new QueryProductTag(){Id = 1003, Name = "Tag 3" },
new QueryProductTag(){Id = 1004, Name = "Tag 4" },
}
};

products = new[] { product1 }.AsQueryable();
ODataQueryContext context = new ODataQueryContext(_model, typeof(QueryProduct)) { RequestContainer = new MockServiceProvider() };

SelectExpandQueryOption selectExpand = new SelectExpandQueryOption(select: null, expand: expand, context: context);

_settings.PageSize = 2;

QueryBinderContext queryBinderContext = new QueryBinderContext(_model, _settings, selectExpand.Context.ElementClrType)
{
NavigationSource = context.NavigationSource
};

// Act
SelectExpandBinder binder = new SelectExpandBinder();
IQueryable queryable = binder.ApplyBind(products, selectExpand.SelectExpandClause, queryBinderContext);

// Assert
Assert.NotNull(queryable);

IEnumerator enumerator = queryable.GetEnumerator();
Assert.True(enumerator.MoveNext());
var product = Assert.IsAssignableFrom<SelectExpandWrapper<QueryProduct>>(enumerator.Current);
Assert.False(enumerator.MoveNext());
Assert.NotNull(product.Instance);
Assert.Equal("Microsoft.AspNetCore.OData.Tests.Query.Expressions.QueryProduct", product.Instance.GetType().ToString());
IEnumerable<SelectExpandWrapper<QueryProductTag>> innerProductTags = product.Container
.ToDictionary(PropertyMapper)["ProductTags"] as IEnumerable<SelectExpandWrapper<QueryProductTag>>;
Assert.NotNull(innerProductTags);

SelectExpandWrapper<QueryProductTag> firstTag = innerProductTags.FirstOrDefault();
SelectExpandWrapper<QueryProductTag> lastTag = innerProductTags.LastOrDefault();

if (expand.EndsWith("desc)"))
{
Assert.Equal("Tag 4", firstTag.Instance.Name);
Assert.Equal("Tag 3", lastTag.Instance.Name);
}
else
{
Assert.Equal("Tag 1", firstTag.Instance.Name);
Assert.Equal("Tag 2", lastTag.Instance.Name);
}
}

[Fact]
public void Bind_GeneratedExpression_ContainsExpandedObject()
{
Expand Down Expand Up @@ -1874,6 +1947,7 @@ public static IEdmModel GetEdmModel()
var customer = builder.EntitySet<QueryCustomer>("Customers").EntityType;
builder.EntitySet<QueryOrder>("Orders");
builder.EntitySet<QueryCity>("Cities");
builder.EntitySet<QueryProduct>("Products");

customer.Collection.Function("IsUpgraded").Returns<bool>().Namespace="NS";
customer.Collection.Action("UpgradeAll").Namespace = "NS";
Expand Down Expand Up @@ -1964,6 +2038,31 @@ public class QueryOrder
public IDictionary<string, object> OrderProperties { get; set; }
}

[DataContract]
public class QueryProduct
{
[DataMember(Name = "ProductId")]
[Key]
public int Id { get; set; }

[DataMember(Name = "ProductName")]
public string Name { get; set; }

[DataMember(Name = "ProductQuantity")]
public int Quantity { get; set; }

[DataMember(Name = "ProductTags")]
public IList<QueryProductTag> Tags { get; set; }
}

public class QueryProductTag
{
[Key]
public int Id { get; set; }

public string Name { get; set; }
}

public class QueryCustomer
{
public int Id { get; set; }
Expand Down