没有这样的表 - 内存中带有 Sqlite 的 EF Core

bie*_*000 12 c# entity-framework-core

我正在尝试设置我的测试环境,但我在使用 Sqlite 适配器时遇到了问题。每个创建的上下文都有相同的连接,因此应该为每个上下文正确构建内存数据库。

但是当我尝试添加新内容时,它会抛出错误:“没有这样的表:%here_is_my_tablename%”。

我觉得我的配置应该不错。

根据:

public abstract class BaseServiceTests : IDisposable
{
    protected readonly SqliteConnection Connection;

    public BaseServiceTests()
    {
        Connection = new SqliteConnection("DataSource=:memory:");
        Connection.Open();
        Assert.NotNull(Connection);

        using (var ctx = BuildCoreContext())
        {
            ctx.Database.EnsureCreated();
        }   

        using (var ctx = BuildWebContext())
        {
            ctx.Database.EnsureCreated();
        }     
    }

    public void Dispose()
    {
        Connection.Close();
    }

    public DbContextOptions<TContext> Options<TContext>() where TContext: DbContext
    {
        var options = new DbContextOptionsBuilder<TContext>()
            .UseSqlite(Connection)
            .Options;

        return options;
    }

    public ServiceRequestCoreContext BuildCoreContext()
    {
        var ctx = new ServiceRequestCoreContext(Options<ServiceRequestCoreContext>(), null);
        ctx.Database.OpenConnection();

        return ctx;
    }

    public ServiceRequestWebContext BuildWebContext()
    {
        var ctx = new ServiceRequestWebContext(Options<ServiceRequestWebContext>(), null);
        ctx.Database.OpenConnection();

        return ctx;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试

public class RequestServiceTests : BaseServiceTests
{
    public async Task Prepare()
    {
        using (var ctx = BuildCoreContext())
        {
            await ctx.RequestTypes.AddAsync(new RequestType((int)RequestTypes.Order, "TestType - test"));
            await ctx.RequestStatuses.AddAsync(new RequestStatus((int)RequestStatuses.AcceptedForVeryfication, "test - test", "test - test"));
            await ctx.Companies.AddAsync(new CustomerCompany(1, "test - test", "Test - test"));
            await ctx.SaveChangesAsync();
        }
    }

    [Fact]
    public async Task when_creating_new_request_it_should_not_be_null()
    {
        //Arrange 
        await Prepare();
        var customerId = 1;
        var iGen = new IdentifyGenerator();

        //Act
        using (var webCtx = BuildWebContext())
        {
            webCtx.Database.OpenConnection();
            var service = new RequestService(webCtx, BuildCoreContext(), iGen);
            await service.CreateAsync(customerId);
            await webCtx.SaveChangesAsync();
        }

        //Assert
        using (var ctx = BuildWebContext())
        {
            ctx.ServiceRequests.Should().HaveCount(1);
            ctx.ServiceRequests.FirstOrDefault().Should().NotBeNull();                
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Sha*_*han 7

为了回答 OP,我认为问题在于访问数据库的多个上下文,如果没有共享缓存,它就无法工作。将您的连接字符串更改为:"DataSource=file::memory:?cache=shared"

对于那些从谷歌来到这里的人,这里有一些其他的事情要记住:

  • 至少有一个连接必须与数据库保持打开状态。
  • 如果要从多个连接访问数据库,则必须使用共享缓存,如下所示: string connectionString = "DataSource=file::memory:?cache=shared";
  • 如果使用 ADO.NET,则官方提供程序无法与 Entity Framework 正常工作。我在测试时遇到了“没有这样的表”错误,即使我已经正确配置了所有内容,但是一旦我从:System.Data.SQLite.SQLiteConnection(System.Data.SQLite.Core nuget 包)更改为 Microsoft 提供程序:Microsoft.Data.Sqlite.SqliteConnection然后错误就消失了。
  • 官方 Sqlite ADO.NET 适配器比 Microsoft适配器快2 倍!因此,除非您绝对必须,否则最好使用官方的 Sqlite 适配器。

示例代码:

[Fact]
public async Task MyTest()
{
    var dbContext = new MyDbContext("DataSource=file:memdb1?mode=memory&cache=shared");

    try
    {
        await dbContext.Database.OpenConnectionAsync();
        // Test your dbContext methods, which has an open connection to the in-memory database
        // If using ADO.NET to make new connections, use Microsoft.Data.Sqlite.SqliteConnection
    }
    finally
    {
        await dbContext.Database.CloseConnectionAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

还记得阅读文档!:)

更新:为了使内存数据库的测试更容易,我创建了一个继承自 DbContext 的 TestContext 以自动处理连接和数据库创建:(这次使用 NUnit)

public sealed class TestContext : UsersContext
{
    public TestContext(string connectionString) : base(connectionString)
    {
        Database.OpenConnection();
        Database.EnsureCreated();
    }

    public override void Dispose()
    {
        Database.CloseConnection();
        base.Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

[Test]
public void AddingUsersShouldIncrementId()
{
    using (var dbContext = new TestContext("DataSource=file::memory:?cache=shared"))
    {
        dbContext.UsersDbSet.Add(new UserEntity());
        dbContext.SaveChanges();

        uint actualId = dbContext.Users.Single().Id;
        Assert.AreEqual(1, actualId);
    }
}
Run Code Online (Sandbox Code Playgroud)


Gáb*_*esz 5

SQLite 内存数据库仅在连接打开时存在。你可以使用不同的DbContext,但是如果连接关闭,内存db将被删除。

例子