简体   繁体   中英

C# In memory databases share indexes?

So I'm working on testing parts of my code adding and removing data in my database. I'm setting up an In memory database for each unit test to make sure that I got a completely "clean slate" for each test. However, I have encountered a very weird issue. I have omitted some code below but it shows my general approach:

[TestFixture]
internal class EventControllerTest
{

    [Test]
    public void CreateEventController()
    {
        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: "CreateEventController1")
            .Options;
        var context = new ApplicationDbContext(options, null);

        //Add eventType.
        realEventService = new EventService(context, currentUserService.Object);
        realEventService.CreateEventType(new EventTypeData
        {
            Color = "Pink"
        });
        //ASSERTS
    }

    [Test]
    public void GetEventController()
    {
        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: "GetEventController1")
            .Options;
        var context = new ApplicationDbContext(options, null);

        //Add eventType.
        realEventService = new EventService(context, currentUserService.Object);
        realEventService.CreateEventType(new EventTypeData
        {
            Color = "Pink",
        });
      //ASSERTS
    }
}

Now, If I run each of these tests by themselves, they pass as I originally check the Id of the EventType, they are both 1. However, if I run all my test in sequence, my second test fails. It fails because the EventType that it adds actually has the id of 2 and not 1! However, the database only contains one entry of an EventType. I have separate names on the databases and to my understanding, this means that they are entirely different. And yet, the auto-incremented index is for some reason just increased and used in my second test. So to clarify:

  • If I run CreateEventController() its EventType entry gets the id of one.
  • If I run GetEventController() its EventType entry gets the id of
    one.
  • If I run CreateEventController() and then GetEventController(),
    the EventType entry in CreateEventController() is 1 and the EventType entry id in GetEventController() is 2!

How can I separate these databases entirely?

Looks like an open issue / bug: https://github.com/aspnet/EntityFrameworkCore/issues/6872

They do offer an extension method as a fix (code lifted as is from there):

public static class DbContextExtensions
{
    public static void ResetValueGenerators(this DbContext context)
    {
        var cache = context.GetService<IValueGeneratorCache>();
        foreach (var keyProperty in context.Model.GetEntityTypes()
            .Select(e => e.FindPrimaryKey().Properties[0])
            .Where(p => p.ClrType == typeof(int)
                        && p.ValueGenerated == ValueGenerated.OnAdd))
        {
            var generator = (ResettableValueGenerator)cache.GetOrAdd(
                keyProperty,
                keyProperty.DeclaringEntityType,
                (p, e) => new ResettableValueGenerator());

            generator.Reset();
        }
    }
}

public class ResettableValueGenerator : ValueGenerator<int>
{
    private int _current;

    public override bool GeneratesTemporaryValues => false;

    public override int Next(EntityEntry entry)
        => Interlocked.Increment(ref _current);

    public void Reset() => _current = 0;
}

To use, call context.ResetValueGenerators(); before the context is used for the first time and any time that EnsureDeleted is called. For example:

using (var context = new BlogContext())
{
    context.ResetValueGenerators();
    context.Database.EnsureDeleted();

    context.Posts.Add(new Post {Title = "Open source FTW", Blog = new Blog {Title = "One Unicorn"}});
    context.SaveChanges();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM