使用 SQLite 测试 ASP Net Core 应用程序抛出未知函数:newid()

mJa*_*Jay 5 c# sqlite unit-testing entity-framework asp.net-core

我正在测试我的服务层,其中包含使用 SQLite 数据库提供程序对存储库的一些调用。我的测试类是按照如下介绍写的:https : //docs.microsoft.com/en-us/ef/core/miscellaneous/testing/sqlite

对于此测试用例中写入数据库的实体,在数据库上生成 Guid:

entity.Property(e => e.Guid).HasDefaultValueSql("newid()");
Run Code Online (Sandbox Code Playgroud)

现在,当尝试添加一个新实体(没有明确设置 Guid)时,我得到以下异常:

SQLite Error 1: 'unknown function: newid()'.
Run Code Online (Sandbox Code Playgroud)

有没有办法解决这个问题? 似乎根本不支持此功能。由于我正在使用的数据库很旧,我害怕找到更多这样的地方可能不起作用。

我的希望是使用 SQLite 获得比使用 InMemoryDatabase 提供程序更好的单元测试,后者并不真正适合测试“关系数据库功能”。但是如果这个问题不能解决,我就卡住了,可能需要坚持集成测试(至少对于我服务的数据访问部分)

tha*_*han 9

如果您引用 Microsoft.Data.Sqlite,您可以在 c# 中创建一个自定义函数来执行此操作

例如:

var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = ":memory:" };
var connection = new SqliteConnection(connectionStringBuilder.ToString());

connection.CreateFunction("newid", () => Guid.NewGuid());
Run Code Online (Sandbox Code Playgroud)

有关 System.Data.SQLite 和 Microsoft.Data.Sqlite 之间的比较,请参见此处


The*_*ock 1

我猜您对于 MySql 或任何其他数据库都会遇到这个问题,uuid()因为newid(). 我的第一个建议是在应用程序端生成 GUID 并将其传递给数据库,但您可能已经想到了这一点但不能。作为解决方法,您可以创建如下扩展方法:

public static class Extensions
{
    private static readonly Dictionary<Type, string> NewIdDictionary = new Dictionary<Type, string>
    {
        { typeof(SqlServerOptionsExtension), "newid()" }
    };

    public static PropertyBuilder<TProperty> HasDefaultValueForSql<TProperty>(this PropertyBuilder<TProperty> propertyBuilder, 
        DbContextOptions contextOptions)
    {
        var result = contextOptions.Extensions.Select(extension =>
        {
            if (!(extension is RelationalOptionsExtension item)) return string.Empty;
            return NewIdDictionary.TryGetValue(item.GetType(), out var sql) ? sql : string.Empty;
        }).SingleOrDefault(s => !string.IsNullOrEmpty(s));

        return propertyBuilder.HasDefaultValueSql(result);
    }
}
Run Code Online (Sandbox Code Playgroud)

尽管没有 SQLite 的等效项,但在将 null 传递给.HasDefaultValueSql. 然后您可以根据需要添加其他扩展类型。