c# - C#在内存数据库中共享索引?
问题描述
所以我正在测试我的部分代码,在我的数据库中添加和删除数据。我正在为每个单元测试设置一个内存数据库,以确保我为每个测试获得一个完全“干净的状态”。但是,我遇到了一个非常奇怪的问题。我在下面省略了一些代码,但它显示了我的一般方法:
[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
}
}
现在,如果我自己运行这些测试中的每一个,它们会通过,因为我最初检查 EventType 的 Id,它们都是 1。但是,如果我按顺序运行所有测试,我的第二个测试会失败。它失败了,因为它添加的 EventType 实际上的 id 是 2 而不是 1!但是,该数据库仅包含一个 EventType 条目。我在数据库上有单独的名称,据我了解,这意味着它们完全不同。然而,自动递增的索引由于某种原因刚刚增加并在我的第二次测试中使用。所以澄清一下:
- 如果我运行 CreateEventController() 它的 EventType 条目将获得 1 的 id。
- 如果我运行 GetEventController() 它的 EventType 条目将获得 1 的 id
。 - 如果我运行 CreateEventController() 然后 GetEventController(),
则 CreateEventController() 中的 EventType 条目为 1,而 GetEventController() 中的 EventType 条目 id 为 2!
我怎样才能完全分离这些数据库?
解决方案
看起来像一个未解决的问题/错误:https ://github.com/aspnet/EntityFrameworkCore/issues/6872
他们确实提供了一种扩展方法作为修复(从那里提取的代码):
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;
}
要使用,请调用 context.ResetValueGenerators(); 在第一次使用上下文之前以及任何时候调用 EnsureDeleted。例如:
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();
}