From 7a3397b8d3803eab54b224197c531f684cdeba35 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Thu, 4 Oct 2018 20:46:35 +0200 Subject: [PATCH] fixed compiled queries not returning a result when applied to different in memory database - locate inmemory tables by entitytype.toString() - removed option useNameMatching as the new method works for all scenarios fixes #13483 --- .../Storage/Internal/InMemoryStore.cs | 31 ++++----- .../Storage/Internal/InMemoryStoreCache.cs | 5 +- .../Query/CompiledQueryInMemoryTest.cs | 68 +++++++++++++++++++ 3 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/EFCore.InMemory/Storage/Internal/InMemoryStore.cs b/src/EFCore.InMemory/Storage/Internal/InMemoryStore.cs index 19006ff1495..fb7535e9b16 100644 --- a/src/EFCore.InMemory/Storage/Internal/InMemoryStore.cs +++ b/src/EFCore.InMemory/Storage/Internal/InMemoryStore.cs @@ -20,31 +20,19 @@ namespace Microsoft.EntityFrameworkCore.InMemory.Storage.Internal public class InMemoryStore : IInMemoryStore { private readonly IInMemoryTableFactory _tableFactory; - private readonly bool _useNameMatching; private readonly object _lock = new object(); - private LazyRef> _tables = CreateTables(); - - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - public InMemoryStore([NotNull] IInMemoryTableFactory tableFactory) - : this(tableFactory, useNameMatching: false) - { - } - + private LazyRef> _tables = CreateTables(); + /// /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// public InMemoryStore( - [NotNull] IInMemoryTableFactory tableFactory, - bool useNameMatching) + [NotNull] IInMemoryTableFactory tableFactory) { _tableFactory = tableFactory; - _useNameMatching = useNameMatching; } /// @@ -101,8 +89,8 @@ public virtual bool Clear() } } - private static LazyRef> CreateTables() - => new LazyRef>(() => new Dictionary()); + private static LazyRef> CreateTables() + => new LazyRef>(() => new Dictionary()); /// /// This API supports the Entity Framework Core infrastructure and is not intended to be used @@ -117,7 +105,7 @@ public virtual IReadOnlyList GetTables(IEntityType entity { foreach (var et in entityType.GetConcreteTypesInHierarchy()) { - var key = _useNameMatching ? (object)et.Name : et; + var key = GetTableKey(et); if (_tables.Value.TryGetValue(key, out var table)) { data.Add(new InMemoryTableSnapshot(et, table.SnapshotRows())); @@ -149,7 +137,7 @@ public virtual int ExecuteTransaction( Debug.Assert(!entityType.IsAbstract()); - var key = _useNameMatching ? (object)entityType.Name : entityType; + var key = GetTableKey(entityType); if (!_tables.Value.TryGetValue(key, out var table)) { _tables.Value.Add(key, table = _tableFactory.Create(entityType)); @@ -186,5 +174,10 @@ public virtual int ExecuteTransaction( return rowsAffected; } + + private string GetTableKey(IEntityType entityType) + { + return entityType.ToString(); + } } } diff --git a/src/EFCore.InMemory/Storage/Internal/InMemoryStoreCache.cs b/src/EFCore.InMemory/Storage/Internal/InMemoryStoreCache.cs index c7248b17328..d29b8bb2742 100644 --- a/src/EFCore.InMemory/Storage/Internal/InMemoryStoreCache.cs +++ b/src/EFCore.InMemory/Storage/Internal/InMemoryStoreCache.cs @@ -16,7 +16,6 @@ namespace Microsoft.EntityFrameworkCore.InMemory.Storage.Internal public class InMemoryStoreCache : IInMemoryStoreCache { private readonly IInMemoryTableFactory _tableFactory; - private readonly bool _useNameMatching; private readonly ConcurrentDictionary _namedStores; /// @@ -41,8 +40,6 @@ public InMemoryStoreCache( if (options?.DatabaseRoot != null) { - _useNameMatching = true; - LazyInitializer.EnsureInitialized( ref options.DatabaseRoot.Instance, () => new ConcurrentDictionary()); @@ -60,6 +57,6 @@ public InMemoryStoreCache( /// directly from your code. This API may change or be removed in future releases. /// public virtual IInMemoryStore GetStore(string name) - => _namedStores.GetOrAdd(name, _ => new InMemoryStore(_tableFactory, _useNameMatching)); + => _namedStores.GetOrAdd(name, _ => new InMemoryStore(_tableFactory)); } } diff --git a/test/EFCore.InMemory.FunctionalTests/Query/CompiledQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/CompiledQueryInMemoryTest.cs index c998339032a..a98fcbe95d5 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/CompiledQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/CompiledQueryInMemoryTest.cs @@ -1,8 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; +using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.EntityFrameworkCore.Query @@ -13,6 +17,70 @@ public CompiledQueryInMemoryTest(NorthwindQueryInMemoryFixture( + o => o.UseInMemoryDatabase(dbName)); + } + } + + [Fact] + public void Query_Different_InMemoryDatabases() + { + var preCompiled = EF.CompileQuery(ctx => ctx.Customers.SingleOrDefault()); + + using (var services = new MyServiceCollection("FOO").BuildServiceProvider()) + { + using (var scope = services.GetRequiredService().CreateScope()) + { + var ctx = scope.ServiceProvider.GetRequiredService(); + + ctx.Database.EnsureDeleted(); + ctx.Database.EnsureCreated(); + + ctx.Add(new Customer { ContactName = "One" }); + + ctx.SaveChanges(); + + var item = preCompiled(ctx); + Assert.Equal("One", item?.ContactName); + } + + using (var scope = services.GetRequiredService().CreateScope()) + { + var ctx = scope.ServiceProvider.GetRequiredService(); + var item = preCompiled(ctx); + Assert.Equal("One", item?.ContactName); + } + } + + using (var services = new MyServiceCollection("BAR").BuildServiceProvider()) + { + using (var scope = services.GetRequiredService().CreateScope()) + { + var ctx = scope.ServiceProvider.GetRequiredService(); + ctx.Database.EnsureDeleted(); + ctx.Database.EnsureCreated(); + + ctx.Add(new Customer { ContactName = "Two" }); + + ctx.SaveChanges(); + + var item = preCompiled(ctx); + Assert.Equal("Two", item?.ContactName); + } + + using (var scope = services.GetRequiredService().CreateScope()) + { + var ctx = scope.ServiceProvider.GetRequiredService(); + var item = preCompiled(ctx); + Assert.Equal("Two", item?.ContactName); + } + } + } [Fact(Skip = "See issue#13857")] public override void DbQuery_query()