【问题标题】:Is there a connection string for InMemoryDatabase?InMemoryDatabase 是否有连接字符串?
【发布时间】:2022-03-16 21:53:35
【问题描述】:

因此,我们在使用 MediatR 的应用程序中使用了 CQRS 模式。我正在开发一个基本的 CRUD API,具有以下规定:

  • GET 调用需要使用 QueryHandlers、Dapper、SQL 从数据库中检索数据。
  • PUT/POST/DELETE 调用需要使用 CommandHandlers/Entity Framework 来修改数据库。

此时我已经按预期工作了。但是,我发现测试是一场噩梦,因为我无法确定访问内存数据库所需的连接字符串。

我已经尝试过connectionString = "Data Source=:memory:;Mode=Memory;Cache=Shared"; 以及这些值的各种排列,但没有任何工作。

我看过 SQLite,但它不喜欢我尝试在启动时注册两个不同的数据库(用于读取的 SQLite 和用于写入的 Microsoft.EntityFrameworkCore.InMemory),我试图获取的对象也具有主键bigint/long 和 SQLite 似乎只能处理 integer/int 类型的主键,因为它会抛出“只有整数类型的主键可以具有自动增量”。

我正在使用类似于以下的代码设置 XUnit 测试:

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
   protected override void ConfigureWebHost(IWebHostBuilder builder)
   {
        builder.ConfigureServices(svcs => 
        {
           services.AddDbContextPool<MyDbContext>(opts =>
           {
              options.UseInMemoryDatabase("MyTestDB");
           });
         
           using var scope = svcs.BuildServiceProvider().CreateScope();
           var scopedSvcs = scope.ServiceProvider;
           var dbSvc = scopedSvcs.GetRequiredService<MyDbContext>();

           dbSvc.Database.EnsureCreated();


           // Do DB Seeding stuff
        });
    }
}

在查询处理程序中,我使用SqlConnection,如下所示:

public class GetModelHandler : IRequestHandler<GetModelRequest, MyModel>
{
   private readonly string _connString;


   public GetModelHandler(string connString) { _connString = connString; }


   public async Task<MyModel> Handle(GetModelRequest req, CancellationToken token)
   {
       using (var conn = new SqlConnection(_connectionString)) 
       {
          conn.Open();
          // set command info and make call
       }
   }
}

所以,TL;DR 的问题是......“是否有一个连接字符串可用于访问 Entity Framework Core In-Memory DB,如果有,我该如何找到它?”

【问题讨论】:

  • @atiyar 我很确定这个问题是尽可能具体的。您确实需要一个连接字符串才能使用 SqlConnection/IDbConnection 连接到数据库。我想知道如何找到内存数据库的连接字符串,以便我可以使用 SqlConnection 而不是 EF 来访问它。
  • @atiyar,您在发表评论之前阅读了问题吗?

标签: c# testing entity-framework-core xunit


【解决方案1】:

当您在内存中运行数据库时,一旦连接关闭,其中的数据就会丢失。如果你想保留数据,你可以使用这个创建一个数据库文件

startup.cs 文件中

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{

  if (env.IsDevelopment())
  {
    app.UseDeveloperExceptionPage();
    app.UseMigrationsEndPoint(); //package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

...

    var connection = new SqliteConnectionStringBuilder(Configuration.GetConnectionString("yourConnection"));
    try
    {

      // Keep this line if you want to recreate the database every time you run your app
      if (File.Exists(connection.DataSource)) File.Delete(connection.DataSource);


      var connectionFolder = Directory.GetParent(connection.DataSource);
      if (!Directory.Exists(connectionFolder.FullName)) Directory.CreateDirectory(connectionFolder.FullName); // Create folder

      File.WriteAllBytes(connection.DataSource, new byte[0]); //Create database

    }
    catch
    {

    }
...
  }
  
var context = app.ApplicationServices.GetRequiredService<IdentityContext>();
context.Database.EnsureCreated();

...
}

对于上面的代码,您需要从依赖注入器容器中停用范围验证。您可以在program.cs 中执行此操作

program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
            .UseDefaultServiceProvider(options => options.ValidateScopes = false); // Add this line.

appsettings.json

{
 ...

  "ConnectionStrings": {
    "yourConnection": "Data Source=./App_Data/appdb.db;Cache=Shared;Mode=ReadWrite;"
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    • 2010-09-30
    • 2011-11-27
    • 2011-09-20
    • 2014-02-09
    相关资源
    最近更新 更多