From 39b4ccc825e1ec7bb4de19fefc502a44736b7a46 Mon Sep 17 00:00:00 2001 From: Smit Patel Date: Fri, 18 Dec 2020 13:05:40 -0800 Subject: [PATCH] InMemory: Wrap composite key selector for owned type in AnonymousObject Resolves #23687 Composite key selector needs wrapper so that we compare them component-wise --- ...yableMethodTranslatingExpressionVisitor.cs | 8 +++ .../Query/QueryBugsInMemoryTest.cs | 57 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs index d5ae34dbb2f..461b9ce7894 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs @@ -1467,6 +1467,7 @@ ProjectionBindingExpression projectionBindingExpression .Select(p => p.ClrType) .Any(t => t.IsNullableType()); + var outerKey = entityShaperExpression.CreateKeyValuesExpression( navigation.IsOnDependent ? foreignKey.Properties @@ -1478,6 +1479,13 @@ ProjectionBindingExpression projectionBindingExpression : foreignKey.Properties, makeNullable); + if (foreignKey.Properties.Count > 1 + && !(AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore23687", out var enabled) && enabled)) + { + outerKey = Expression.New(AnonymousObject.AnonymousObjectCtor, outerKey); + innerKey = Expression.New(AnonymousObject.AnonymousObjectCtor, innerKey); + } + var outerKeySelector = Expression.Lambda(_expressionTranslator.Translate(outerKey), _queryExpression.CurrentParameter); var innerKeySelector = Expression.Lambda( _expressionTranslator.Translate(innerKey), innerQueryExpression.CurrentParameter); diff --git a/test/EFCore.InMemory.FunctionalTests/Query/QueryBugsInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/QueryBugsInMemoryTest.cs index 157c8cee064..b9237457dea 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/QueryBugsInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/QueryBugsInMemoryTest.cs @@ -1103,6 +1103,63 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) #endregion + #region Issue23687 + + [ConditionalFact] + public virtual void Owned_reference_with_composite_key() + { + using (CreateScratch(Seed23687, "23687")) + { + using var context = new MyContext23687(); + + var query = context.Table.ToList(); + + var root = Assert.Single(query); + Assert.Equal("A", root.OwnedProp.A); + Assert.Equal("B", root.OwnedProp.B); + } + } + + private static void Seed23687(MyContext23687 context) + { + context.Table.Add(new Root23687 { Id1 = 1, Id2 = 11, OwnedProp = new OwnedClass23687 { A = "A", B = "B" } }); + + context.SaveChanges(); + } + + [Owned] + public class OwnedClass23687 + { + public string A { get; set; } + public string B { get; set; } + } + + public class Root23687 + { + public int Id1 { get; set; } + public int Id2 { get; set; } + public OwnedClass23687 OwnedProp { get; set; } + } + + private class MyContext23687 : DbContext + { + public DbSet Table { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder + .UseInternalServiceProvider(InMemoryFixture.DefaultServiceProvider) + .UseInMemoryDatabase("23687"); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasKey(e => new { e.Id1, e.Id2 }); + } + } + + #endregion + #region SharedHelper private static InMemoryTestStore CreateScratch(Action seed, string databaseName)