简体   繁体   English

C#在内存数据库中共享索引?

[英]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. 现在,如果我自己运行这些测试中的每一个,它们会在我最初检查EventType的Id时通过,它们都是1.但是,如果我按顺序运行所有测试,则第二次测试失败。 It fails because the EventType that it adds actually has the id of 2 and not 1! 它失败了,因为它添加的EventType实际上具有2而不是1的id! However, the database only contains one entry of an EventType. 但是,数据库仅包含一个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. 如果我运行CreateEventController(),其EventType条目的id为1。
  • If I run GetEventController() its EventType entry gets the id of 如果我运行GetEventController(),它的EventType条目获取id
    one. 一。
  • If I run CreateEventController() and then GetEventController(), 如果我运行CreateEventController()然后运行GetEventController(),
    the EventType entry in CreateEventController() is 1 and the EventType entry id in GetEventController() is 2! CreateEventController()中的EventType条目为1,GetEventController()中的EventType条目ID为2!

How can I separate these databases entirely? 如何完全分离这些数据库?

Looks like an open issue / bug: https://github.com/aspnet/EntityFrameworkCore/issues/6872 看起来像一个开放的问题/错误: 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(); 要使用,请调用context.ResetValueGenerators(); before the context is used for the first time and any time that EnsureDeleted is called. 在第一次使用上下文之前以及调用EnsureDeleted的任何时间。 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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