Skip to content

Commit 5c3bed8

Browse files
committed
[2.1.5] Query: Improve logic to find underlying property for projection
Issue: GroupJoin-DefaultIfEmpty aka left outer join introduced NullableExpression around the property which we fail to find hence we use wrong type mapping which expect int32 but we get back int16 from database Resolves #13025
1 parent 383a589 commit 5c3bed8

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

src/EFCore.Relational/Extensions/RelationalExpressionExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ public static IProperty FindProperty([NotNull] this Expression expression, [NotN
8989
return columnReferenceExpression.Expression.FindProperty(targetType);
9090
case AliasExpression aliasExpression:
9191
return aliasExpression.Expression.FindProperty(targetType);
92+
case NullableExpression nullableExpression
93+
when !AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue13025", out var isEnabled) || !isEnabled:
94+
return nullableExpression.Operand.FindProperty(targetType);
9295
case UnaryExpression unaryExpression:
9396
return unaryExpression.Operand.FindProperty(targetType);
9497
case SqlFunctionExpression functionExpression:

test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3472,6 +3472,90 @@ public class MaumarEntity11818
34723472

34733473
#endregion
34743474

3475+
#region Bug13025
3476+
3477+
[Fact]
3478+
public virtual void Find_underlying_property_after_GroupJoin_DefaultIfEmpty()
3479+
{
3480+
using (CreateDatabase13025())
3481+
{
3482+
using (var context = new MyContext13025(_options))
3483+
{
3484+
var query = (from e in context.Employees
3485+
join d in context.EmployeeDevices
3486+
on e.Id equals d.EmployeeId into grouping
3487+
from j in grouping.DefaultIfEmpty()
3488+
select new Holder13025
3489+
{
3490+
Name = e.Name,
3491+
DeviceId = j.DeviceId
3492+
}).ToList();
3493+
3494+
}
3495+
}
3496+
}
3497+
3498+
public class Holder13025
3499+
{
3500+
public string Name { get; set; }
3501+
public int? DeviceId { get; set; }
3502+
}
3503+
3504+
private SqlServerTestStore CreateDatabase13025()
3505+
{
3506+
return CreateTestStore(
3507+
() => new MyContext13025(_options),
3508+
context =>
3509+
{
3510+
context.AddRange(
3511+
new Employee13025
3512+
{
3513+
Name = "Test1",
3514+
Devices = new List<EmployeeDevice13025>
3515+
{
3516+
new EmployeeDevice13025
3517+
{
3518+
DeviceId = 1,
3519+
Device = "Battery"
3520+
}
3521+
}
3522+
});
3523+
3524+
context.SaveChanges();
3525+
ClearLog();
3526+
});
3527+
}
3528+
3529+
public class MyContext13025 : DbContext
3530+
{
3531+
public DbSet<Employee13025> Employees { get; set; }
3532+
public DbSet<EmployeeDevice13025> EmployeeDevices { get; set; }
3533+
public MyContext13025(DbContextOptions options)
3534+
: base(options)
3535+
{
3536+
}
3537+
protected override void OnModelCreating(ModelBuilder modelBuilder)
3538+
{
3539+
}
3540+
}
3541+
public class Employee13025
3542+
{
3543+
public int Id { get; set; }
3544+
public string Name { get; set; }
3545+
public ICollection<EmployeeDevice13025> Devices { get; set; }
3546+
}
3547+
3548+
public class EmployeeDevice13025
3549+
{
3550+
public int Id { get; set; }
3551+
public short DeviceId { get; set; }
3552+
public int EmployeeId { get; set; }
3553+
public string Device { get; set; }
3554+
public Employee13025 Employee { get; set; }
3555+
}
3556+
3557+
#endregion
3558+
34753559
private DbContextOptions _options;
34763560

34773561
private SqlServerTestStore CreateTestStore<TContext>(
@@ -3488,6 +3572,7 @@ private SqlServerTestStore CreateTestStore<TContext>(
34883572
context.Database.EnsureCreated();
34893573
contextInitializer?.Invoke(context);
34903574
}
3575+
34913576
return testStore;
34923577
}
34933578

0 commit comments

Comments
 (0)