Skip to content

Commit

Permalink
fixes #1044, revert the changes for duplicated left JOIN changes. Add…
Browse files Browse the repository at this point in the history
… the regression tests. Update the version to 8.2.3 (#1045)
  • Loading branch information
xuzhg authored Sep 6, 2023
1 parent 2bde4e5 commit fce1c61
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 165 deletions.
5 changes: 0 additions & 5 deletions src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9624,11 +9624,6 @@
Basically for $compute in $select and $expand
</summary>
</member>
<member name="P:Microsoft.AspNetCore.OData.Query.Expressions.QueryBinderContext.QueryProvider">
<summary>
Gets or sets the query provider.
</summary>
</member>
<member name="M:Microsoft.AspNetCore.OData.Query.Expressions.QueryBinderContext.GetParameter(System.String)">
<summary>
Gets the parameter using parameter name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,6 @@ public static IQueryable ApplyBind(this ISelectExpandBinder binder, IQueryable s
throw Error.ArgumentNull(nameof(context));
}

if (string.IsNullOrEmpty(context.QueryProvider))
{
context.QueryProvider = source.Provider.GetType().Namespace;
}

Type elementType = context.ElementClrType;

LambdaExpression projectionLambda = binder.BindSelectExpand(selectExpandClause, context) as LambdaExpression;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ public QueryBinderContext(QueryBinderContext context, ODataQuerySettings querySe

ElementType = Model.GetEdmTypeReference(ElementClrType)?.Definition;

QueryProvider = context.QueryProvider;

if (ElementType == null)
{
throw new ODataException(Error.Format(SRResources.ClrTypeNotInModel, ElementClrType.FullName));
Expand Down Expand Up @@ -170,11 +168,6 @@ public QueryBinderContext(QueryBinderContext context, ODataQuerySettings querySe
/// </summary>
public Expression Source { get;set; }

/// <summary>
/// Gets or sets the query provider.
/// </summary>
internal string QueryProvider { get; set; }

/// <summary>
/// Gets the parameter using parameter name.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,23 +368,9 @@ internal Expression ProjectElement(QueryBinderContext context, Expression source
bool isSelectedAll = IsSelectAll(selectExpandClause);
if (isSelectedAll)
{
// If we have an EF query provider, then we remove the non-structural properties. The reason for this is to avoid
// Creating an expression that will generate duplicate LEFT joins when a LEFT join already exists in the IQueryable
// as observed here: https://github.com/OData/AspNetCoreOData/issues/497

Expression updatedExpression = null;
if (IsEfQueryProvider(context))
{
updatedExpression = SelectExpandBinder.RemoveNonStructucalProperties(context, source, structuredType);
}
else
{
updatedExpression = source;
}

// Initialize property 'Instance' on the wrapper class
wrapperProperty = wrapperType.GetProperty("Instance");
wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, updatedExpression));
wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, source));

wrapperProperty = wrapperType.GetProperty("UseInstanceForProperties");
wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, Expression.Constant(true)));
Expand Down Expand Up @@ -441,52 +427,6 @@ internal Expression ProjectElement(QueryBinderContext context, Expression source
return Expression.MemberInit(Expression.New(wrapperType), wrapperTypeMemberAssignments);
}

// Generates the expression
// { Instance = new Customer() {Id = $it.Id, Name= $it.Name}}
private static Expression RemoveNonStructucalProperties(QueryBinderContext context, Expression source, IEdmStructuredType structuredType)
{
IEdmModel model = context.Model;
Expression updatedSource = null;

Type elementType = source.Type;
IEnumerable<IEdmStructuralProperty> structuralProperties = structuredType.StructuralProperties();

PropertyInfo[] props = elementType.GetProperties();
List<MemberBinding> bindings = new List<MemberBinding>();

foreach (PropertyInfo prop in props)
{
foreach (var sp in structuralProperties)
{
if (prop.CanWrite && model.GetClrPropertyName(sp) == prop.Name)
{
MemberExpression propertyExpression = Expression.Property(source, prop);
bindings.Add(Expression.Bind(prop, propertyExpression));
break;
}
}
}

NewExpression newExpression = Expression.New(source.Type);
updatedSource = Expression.MemberInit(newExpression, bindings);

return updatedSource;
}

private bool IsEfQueryProvider(QueryBinderContext context)
{
if (context.QueryProvider != null &&
context.QueryProvider == HandleNullPropagationOptionHelper.EntityFrameworkQueryProviderNamespace ||
context.QueryProvider == HandleNullPropagationOptionHelper.ObjectContextQueryProviderNamespaceEF5 ||
context.QueryProvider == HandleNullPropagationOptionHelper.ObjectContextQueryProviderNamespaceEF6 ||
context.QueryProvider == HandleNullPropagationOptionHelper.ObjectContextQueryProviderNamespaceEFCore2)
{
return true;
}

return false;
}

private static bool ParseComputedDynamicProperties(QueryBinderContext context, IList<DynamicPathSegment> dynamicPathSegments, bool isSelectedAll,
out IList<string> computedProperties)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="6.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//-----------------------------------------------------------------------------
// <copyright file="RegressionsController.cs" company=".NET Foundation">
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// See License.txt in the project root for license information.
// </copyright>
//------------------------------------------------------------------------------

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.EntityFrameworkCore;

namespace Microsoft.AspNetCore.OData.E2E.Tests.Regressions
{
public class UsersController : Controller
{
private readonly RegressionsDbContext _dbContext;

public UsersController(RegressionsDbContext dbContext)
{
dbContext.Database.EnsureCreated();
_dbContext = dbContext;
if (!_dbContext.Users.Any())
{
_dbContext.DataFiles.Add(new DataFile
{
FileId = 1,
FileName = "76x473626.pdf"
});

DataFile dataFile2 = new DataFile
{
FileId = 2,
FileName = "uyr65euit5.pdf"
};
_dbContext.DataFiles.Add(dataFile2);

_dbContext.DataFiles.Add(new DataFile
{
FileId = 3,
FileName = "hj7x87643.pdf"
});

_dbContext.Users.Add(new User
{
UserId = 1,
Name = "Alex",
Age = 35,
DataFileRef = null,
Files = null
});

_dbContext.Users.Add(new User
{
UserId = 2,
Name = "Amanda",
Age = 29,
DataFileRef = 2,
Files = dataFile2
});

_dbContext.Users.Add(new User
{
UserId = 3,
Name = "Lara",
Age = 25,
DataFileRef = null,
Files = null
});

_dbContext.SaveChanges();
}
}

[HttpGet]
[EnableQuery]
public IQueryable<User> Get()
{
IQueryable<User> data = _dbContext.Users.AsQueryable();
return data;
}

[HttpGet]
[EnableQuery]
public IActionResult Get(int key)
{
User data = _dbContext.Users.Include(c => c.Files).FirstOrDefault(c => c.UserId == key);
if (data == null)
{
return NotFound();
}

return Ok(data);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//-----------------------------------------------------------------------------
// <copyright file="RegressionsDataModel.cs" company=".NET Foundation">
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// See License.txt in the project root for license information.
// </copyright>
//------------------------------------------------------------------------------

using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;

namespace Microsoft.AspNetCore.OData.E2E.Tests.Regressions
{
public class User
{
[Key]
public int UserId { get; set; }

[Required]
public string Name { get; set; }

[Required]
public int Age { get; set; }

//Navigations
[ForeignKey("Files")]
public int? DataFileRef { get; set; }

public virtual DataFile Files { get; set; }
}

public class DataFile
{
[Key]
public int FileId { get; set; }

[Required]
public string FileName { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
// <copyright file="RegressionsDbContext.cs" company=".NET Foundation">
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// See License.txt in the project root for license information.
// </copyright>
//------------------------------------------------------------------------------

using Microsoft.EntityFrameworkCore;

namespace Microsoft.AspNetCore.OData.E2E.Tests.Regressions
{
public class RegressionsDbContext : DbContext
{
public RegressionsDbContext(DbContextOptions<RegressionsDbContext> options)
: base(options)
{
}

public DbSet<User> Users { get; set; }

public DbSet<DataFile> DataFiles { get; set; }
}
}
Loading

0 comments on commit fce1c61

Please sign in to comment.