Skip to content

Commit

Permalink
Query: Unwrap type conversion when matching member on MemberInitExpre…
Browse files Browse the repository at this point in the history
…ssion

Resolves #20097
  • Loading branch information
smitpatel committed Mar 10, 2020
1 parent a676fae commit 62b88f3
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 11 deletions.
6 changes: 4 additions & 2 deletions src/EFCore/Query/ReplacingExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ protected override Expression VisitMember(MemberExpression memberExpression)
}
}

if (innerExpression is MemberInitExpression memberInitExpression
var mayBeMemberInitExpression = innerExpression.UnwrapTypeConversion(out var convertedType);
if (mayBeMemberInitExpression is MemberInitExpression memberInitExpression
&& memberInitExpression.Bindings.SingleOrDefault(
mb => mb.Member.IsSameAs(memberExpression.Member)) is MemberAssignment memberAssignment)
{
Expand All @@ -101,7 +102,8 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
}
}

if (newEntityExpression is MemberInitExpression memberInitExpression
var mayBeMemberInitExpression = newEntityExpression.UnwrapTypeConversion(out var convertedType);
if (mayBeMemberInitExpression is MemberInitExpression memberInitExpression
&& memberInitExpression.Bindings.SingleOrDefault(
mb => mb.Member.Name == propertyName) is MemberAssignment memberAssignment)
{
Expand Down
158 changes: 149 additions & 9 deletions test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7044,15 +7044,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CustomerFilter19708>()
.HasQueryFilter(e => (from a in (from c in Customers
join cm in CustomerMemberships on c.Id equals cm.CustomerId into g
from cm in g.DefaultIfEmpty()
select new
{
c.Id,
CustomerMembershipId = (int?)cm.Id
})
where a.CustomerMembershipId != null && a.Id == e.CustomerId
select a).Count() > 0)
join cm in CustomerMemberships on c.Id equals cm.CustomerId into g
from cm in g.DefaultIfEmpty()
select new
{
c.Id,
CustomerMembershipId = (int?)cm.Id
})
where a.CustomerMembershipId != null && a.Id == e.CustomerId
select a).Count() > 0)
.HasKey(e => e.CustomerId);

modelBuilder.Entity<CustomerView19708>().HasNoKey().ToQuery(Build_Customers_Sql_View_InMemory());
Expand Down Expand Up @@ -7107,6 +7107,146 @@ private class CustomerView19708

#endregion

#region Issue20097

[ConditionalFact]
public void Implicit_interface_casting_though_generic_method()
{
using var _ = CreateDatabase20097();
using var context = new BugContext20097(_options);

var originalQuery = context.Entities.Select(a => new MyModel20097 { Id = a.Id });
var query = AddFilter(originalQuery, 1).ToList();

Assert.Single(query);

AssertSql(
@"@__id_0='1'
SELECT [e].[Id]
FROM [Entities] AS [e]
WHERE [e].[Id] = @__id_0");
}

[ConditionalFact]
public void Explicit_interface_casting_though_generic_method()
{
using var _ = CreateDatabase20097();
using var context = new BugContext20097(_options);

var originalQuery = context.Entities.Select(a => new MyModel20097 { Id = a.Id });
var query = originalQuery.Where<IHaveId20097>(a => a.Id == 1).ToList();

Assert.Single(query);

AssertSql(
@"SELECT [e].[Id]
FROM [Entities] AS [e]
WHERE [e].[Id] = CAST(1 AS bigint)");
}

[ConditionalFact]
public void Explicit_interface_casting_in_lambda()
{
using var _ = CreateDatabase20097();
using var context = new BugContext20097(_options);

var originalQuery = context.Entities.Select(a => new MyModel20097 { Id = a.Id });
var query = originalQuery.Where(a => ((IHaveId20097)a).Id == 1).ToList();

Assert.Single(query);

AssertSql(
@"SELECT [e].[Id]
FROM [Entities] AS [e]
WHERE [e].[Id] = CAST(1 AS bigint)");
}

[ConditionalFact]
public void Explicit_interface_soft_casting_in_lambda()
{
using var _ = CreateDatabase20097();
using var context = new BugContext20097(_options);

var originalQuery = context.Entities.Select(a => new MyModel20097 { Id = a.Id });
var query = originalQuery.Where(a => (a as IHaveId20097).Id == 1).ToList();

Assert.Single(query);

AssertSql(
@"SELECT [e].[Id]
FROM [Entities] AS [e]
WHERE [e].[Id] = CAST(1 AS bigint)");
}

[ConditionalFact]
public void Explicit_interface_casting_checked_in_lambda()
{
using var _ = CreateDatabase20097();
using var context = new BugContext20097(_options);

var originalQuery = context.Entities.Select(a => new MyModel20097 { Id = a.Id });
checked
{
var query = originalQuery.Where(a => ((IHaveId20097)a).Id == 1).ToList();
Assert.Single(query);
}

AssertSql(
@"SELECT [e].[Id]
FROM [Entities] AS [e]
WHERE [e].[Id] = CAST(1 AS bigint)");
}

private static IQueryable<T> AddFilter<T>(IQueryable<T> query, long id)
where T : IHaveId20097
{
return query.Where(a => a.Id == id);
}

private SqlServerTestStore CreateDatabase20097()
=> CreateTestStore(
() => new BugContext20097(_options),
context =>
{
context.AddRange(new Entity20097());

context.SaveChanges();

ClearLog();
});

private class BugContext20097 : DbContext
{
public BugContext20097(DbContextOptions options)
: base(options)
{
}

public DbSet<Entity20097> Entities { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}

private class Entity20097
{
public long Id { get; set; }
}

private interface IHaveId20097
{
long Id { get; }
}

private class MyModel20097 : IHaveId20097
{
public long Id { get; set; }
}

#endregion

private DbContextOptions _options;

private SqlServerTestStore CreateTestStore<TContext>(
Expand Down

0 comments on commit 62b88f3

Please sign in to comment.