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

PoC for EF Core 5 (and may be 3.1) support #2179

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
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 @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.AspNet.OData.Common;
using Microsoft.Extensions.DependencyInjection;
Expand All @@ -16,6 +17,7 @@ namespace Microsoft.AspNet.OData.Formatter.Serialization
/// <summary>
/// The default <see cref="ODataSerializerProvider"/>.
/// </summary>
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Class coupling acceptable")]
public partial class DefaultODataSerializerProvider : ODataSerializerProvider
{
private readonly IServiceProvider _rootContainer;
Expand Down Expand Up @@ -75,6 +77,7 @@ public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference ed
}

/// <inheritdoc />
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Class coupling acceptable")]
internal ODataSerializer GetODataPayloadSerializerImpl(Type type, Func<IEdmModel> modelFunction, ODataPath path, Type errorType)
{
if (type == null)
Expand Down Expand Up @@ -130,10 +133,13 @@ internal ODataSerializer GetODataPayloadSerializerImpl(Type type, Func<IEdmModel
return GetEdmTypeSerializer(edmType);
}
}
else
else if (type.IsGenericType() && EdmLibHelpers.IsDynamicTypeWrapper(type.GetGenericArguments()[0]))
{
return null;
// $apply

return GetEdmTypeSerializer(path.Segments.OfType<EntitySetSegment>().FirstOrDefault().EdmType.ToEdmTypeReference(true));
}
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.OData.Common;
using Microsoft.AspNet.OData.Interfaces;
using Microsoft.AspNet.OData.Query;
Expand Down Expand Up @@ -283,6 +284,11 @@ private set
internal IEdmTypeReference GetEdmType(object instance, Type type)
{
IEdmTypeReference edmType;
if (type != null && type.IsGenericType() && EdmLibHelpers.IsDynamicTypeWrapper(type.GetGenericArguments()[0]))
{
return this.Path.Segments.OfType<EntitySetSegment>().FirstOrDefault()?.EdmType?.ToEdmTypeReference(true);
}


IEdmObject edmObject = instance as IEdmObject;
if (edmObject != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ private IQueryable FlattenReferencedProperties(IQueryable query)
{
if (_aggregateExpressions != null
&& _aggregateExpressions.OfType<AggregateExpression>().Any(e => e.Method != AggregationMethod.VirtualPropertyCount)
&& _groupingProperties != null
&& _groupingProperties.Any()
//&& _groupingProperties != null
//&& _groupingProperties.Any()
&& (FlattenedPropertyContainer == null || !FlattenedPropertyContainer.Any()))
{
var wrapperType = typeof(FlatteningWrapper<>).MakeGenericType(this.ElementType);
Expand Down Expand Up @@ -347,11 +347,11 @@ private Expression CreateEntitySetAggregateExpression(

// Create method to get property collections to aggregate
MethodInfo selectManyMethod
= ExpressionHelperMethods.EnumerableSelectManyGeneric.MakeGenericMethod(baseElementType, selectedElementType);
= ExpressionHelperMethods.EnumerableSelectManyGeneric.MakeGenericMethod(baseType == this.ElementType ? this.ElementType: baseElementType, selectedElementType);

// Create the lambda that acceses the property in the selectMany clause.
var selectManyParam = Expression.Parameter(baseElementType, "$it");
var propertyExpression = Expression.Property(selectManyParam, expression.Expression.NavigationProperty.Name);
var selectManyParam = baseType == this.ElementType ? this.LambdaParameter : Expression.Parameter(baseElementType, "$it");
var propertyExpression = Expression.Property(source, expression.Expression.NavigationProperty.Name);
var selectManyLambda = Expression.Lambda(propertyExpression, selectManyParam);

// Get expression to get collection of entities
Expand Down Expand Up @@ -402,16 +402,16 @@ private Expression CreatePropertyAggregateExpression(ParameterExpression accum,
// we need cast it to IEnumerable<baseType> during expression building (IEnumerable)$it
// however for EF6 we need to use $it.AsQueryable() due to limitations in types of casts that will properly translated
Expression asQuerableExpression = null;
if (ClassicEF)
{
//if (ClassicEF)
//{
var asQuerableMethod = ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(baseType);
asQuerableExpression = Expression.Call(null, asQuerableMethod, accum);
}
else
{
var queryableType = typeof(IEnumerable<>).MakeGenericType(baseType);
asQuerableExpression = Expression.Convert(accum, queryableType);
}
//}
//else
//{
// var queryableType = typeof(IEnumerable<>).MakeGenericType(baseType);
// asQuerableExpression = Expression.Convert(accum, queryableType);
//}

// $count is a virtual property, so there's not a propertyLambda to create.
if (expression.Method == AggregationMethod.VirtualPropertyCount)
Expand Down Expand Up @@ -586,6 +586,7 @@ private IQueryable BindGroupBy(IQueryable query)
// .GroupBy($it => new NoGroupByWrapper())
groupLambda = Expression.Lambda(Expression.New(this._groupByClrType), this.LambdaParameter);
}


return ExpressionHelpers.GroupBy(query, groupLambda, elementType, this._groupByClrType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,9 @@ public async Task AggregateVirtualCountWorks()
HttpResponseMessage response = await client.SendAsync(request);

// Assert
var res = await response.Content.ReadAsStringAsync();
JObject json = JObject.Parse(res);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
JObject json = JObject.Parse(await response.Content.ReadAsStringAsync());
JToken value = json["value"].Children().First();

var anonymousResponse = new { Count = 0 };
Expand Down Expand Up @@ -623,8 +624,10 @@ public async Task MethodsNotDefinedHaveAppropriateAnswer(string query)
[InlineData("?$apply=aggregate(Order/Price with min as Result)", "0")]
[InlineData("?$apply=aggregate(Order/Price with max as Result)", "900")]
[InlineData("?$apply=aggregate(Order/Price with average as Result)", "450")]
#if !NETCORE3x
[InlineData("?$apply=aggregate(Order/Price with countdistinct as Result)", "10")]
[InlineData("?$apply=aggregate(Order/Price with countdistinct as Result)&$orderby=Result", "10")]
#endif
public async Task AggregateMethodWorks(string query, string expectedResult)
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ protected override void OnModelCreating(EntityFrameworkCore.ModelBuilder modelBu
modelBuilder.Entity<EpCustomer>().OwnsOne(c => c.HomeAddress);
modelBuilder.Entity<EpCustomer>().OwnsMany(c => c.FavoriteAddresses, a =>
{
a.HasForeignKey("OwnerId");
a.WithOwner().HasForeignKey("OwnerId");
a.Property<int>("Id");
a.HasKey("Id");
});

//modelBuilder.Entity<EpCustomer>().Navigation(c => c.FavoriteAddresses).

// But, in EF Core 3.x, it seems we can only use the following codes:
// modelBuilder.Entity<EpCustomer>().OwnsOne(c => c.HomeAddress).WithOwner();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<AssemblyName>Microsoft.Test.E2E.AspNetCore3x.OData</AssemblyName>
<OutputPath>$(WebStackRootPath)bin\$(Configuration)\E2ETest\AspNetCore\</OutputPath>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(WebStackRootPath)sln\</SolutionDir>
<DefineConstants>$(DefineConstants);NETCORE;PORTABLELIB</DefineConstants>
<DefineConstants>$(DefineConstants);NETCORE;NETCORE3x;PORTABLELIB</DefineConstants>
<FileAlignment>512</FileAlignment>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
Expand All @@ -34,10 +34,11 @@
<PackageReference Include="xunit.assert" Version="2.4.1" />
<PackageReference Include="xunit.core" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0-preview.4.20220.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.0-preview.4.20220.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0-preview.4.20220.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="5.0.0-preview.4.20220.10" />
<PackageReference Include="System.Diagnostics.EventLog" Version="4.7.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ public async Task AggregationOnEntitySetWorksWithPropertyAggregation()
HttpResponseMessage response = client.SendAsync(request).Result;

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var result = await response.Content.ReadAsObject<JObject>();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var value = result["value"];
var totalId = value.First["TotalId"].ToObject<int>();
var orders = value.First["Orders"];
Expand Down
Loading