内存中的EF Core SQLite异常:SQLite错误1:'接近“最大值”:语法错误'

i86rm4rw  于 2023-03-13  发布在  SQLite
关注(0)|答案(2)|浏览(152)

我正在为单元测试创建SQLite内存数据库:

var connection = new SqliteConnection("DataSource=:memory:");
        connection.Open();

        try
        {
            var options = new DbContextOptionsBuilder<BloggingContext>()
                .UseSqlite(connection)
                .Options;

            // Create the schema in the database
            using (var context = new BloggingContext(options))
            {
                context.Database.EnsureCreated();
            }

            // Run the test against one instance of the context
            using (var context = new BloggingContext(options))
            {
                var service = new BlogService(context);
                service.Add("http://sample.com");
            }

            // Use a separate instance of the context to verify correct data was saved to database
            using (var context = new BloggingContext(options))
            {
                Assert.AreEqual(1, context.Blogs.Count());
                Assert.AreEqual("http://sample.com", context.Blogs.Single().Url);
            }
        }

**上下文.数据库.EnsureCreated();*失败,出现异常: 消息:Microsoft数据库异常:SQLite错误1:'接近“最大值”:语法错误'. *

github issue说:* 这里的问题是varchar(max)是SqlServer特定的类型。搭建不应将其添加为关系类型,因为它会传递给其他提供程序中的迁移,这很容易在迁移时生成无效的sql。*

但是如果我的数据库包含许多varchar(max)列,我如何使用SQLite in Memory进行单元测试呢?

vjhs03f7

vjhs03f71#

我没有找到一个直接的解决方案,但已经开始使用配置文件的变通方案。你没有指出,如果你使用的EF配置,所以原谅基本的,如果不需要。
在DbContext中放置以下内容:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfigurationsFromAssembly(typeof(ChildrensSsiContext).Assembly);
}

现在创建一个静态类,如下所示,它将接受你的属性并处理配置。

internal static class ConfigurationHelper
{
    internal static void ConfigureVarcharMax(PropertyBuilder<string> propertyBuilder, bool isRequired = true)
    {
        propertyBuilder
            .IsRequired(isRequired)
            //.HasColumnType("varchar(max)");
            .HasColumnType("text");
    }
}

为要配置的每个实体创建Configuration类

public class MyEntityWithVarcharMaxConfiguration
    : IEntityTypeConfiguration<MyEntityWithVarcharMax>
{
    public void Configure(EntityTypeBuilder<MyEntityWithVarcharMax> builder)
    {
        ConfigurationHelper.ConfigureVarcharMax(builder.Property(e => e.MyVarcharMaxProperty));
    }
}

保持HasColumnType(“text”)不加注解以进行测试,然后在添加迁移时注解该行并取消注解HasColumnType(“varchar(max)”)。
这是一个痛苦,你需要记住这样做,但它是一个相当简单的变通办法。

qxsslcnc

qxsslcnc2#

我的解决方案:在AppDbContext中定义一个标志为true(在我的例子中,意味着这是针对我的SqlServer的)。每当AppDbContext从Test项目初始化时,将该标志设置为false(因为对于测试,我们使用SqlLite)。
最后,在OnModelCreating中,为那些具有nvarchar(max)的实体检查标志,如果为false(意味着我正在运行测试),则将那些nvarchar(max)属性的ColumnTypes设置为Text。
在AppDbContext中:

public static bool IsSqlServer = true;

在AppDbContext.OnModelCreating中,为具有这些nvarchar属性的实体执行以下操作,以将类型从nvarchar(max)更改为text:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<YourType>( entity => 
   {
      if (!IsSqlServer)
         entity.Property(YourPropertyName).HasColumnType("text");
   }
}

最后,在您的测试项目初始化中,将标志设置为false以更改类型,这样它就不会失败。

AppDbContext.IsSqlServer = false;

相关问题