首页 > 数据库 >EFCore执行自定义SQL时格式化错误:Input string was not in a correct format.

EFCore执行自定义SQL时格式化错误:Input string was not in a correct format.

时间:2024-08-04 14:28:59浏览次数:7  
标签:remark string 自定义 format age SQL EFCore sql var

  记录一下EFCore执行自定义SQL报System.FormatException异常的问题,这个异常可能是“Input string was not in a correct format.”,也可能是其它格式化异常,比如:System.ArgumentException:“Format of the initialization string does not conform to specification starting at index 0.”,总之就是格式化错误。

  首先,说明一下,我这边使用的是.net6。

  其次,我们如果要使用EFCore执行自定义的SQL,对于查询语句,不同版本的支持不同,比如我这里使用的.net6,它就没有提供使用EFCore执行自定义SQL的方法,但是.net6后续版本就有了,对于非查询语句,比如增删改,我们可以使用DbContext.Database.ExecuteSqlRaw 的方法和它的异步方法DbContext.Database.ExecuteSqlRawAsync 来来实现,但是需要注意字符串的格式化问题。

  比如我执行这个SQL语句:

    var sql = "INSERT INTO test(name,age,remark)VALUES('zhangsan',20,'remark:{ age is 20}')";
    var result = await dbContext.Database.ExecuteSqlRawAsync(sql);

  执行后报错:System.FormatException:“Input string was not in a correct format.”

  通过查看源码,发现报错是在Microsoft.EntityFrameworkCore.Storage.Internal.RawSqlCommandBuilderBuild 方法:

    public class RawSqlCommandBuilder : IRawSqlCommandBuilder
    {
        public virtual RawSqlCommand Build(string sql, IEnumerable<object> parameters)
        {
            //省略部分代码...

            foreach (var parameter in parameters)
            {
                if (parameter is DbParameter dbParameter)
                {
                    if (string.IsNullOrEmpty(dbParameter.ParameterName))
                    {
                        dbParameter.ParameterName = _sqlGenerationHelper.GenerateParameterName(parameterNameGenerator.GenerateNext());
                    }

                    substitutions.Add(_sqlGenerationHelper.GenerateParameterName(dbParameter.ParameterName));
                    relationalCommandBuilder.AddRawParameter(dbParameter.ParameterName, dbParameter);
                }
                else
                {
                    var parameterName = parameterNameGenerator.GenerateNext();
                    var substitutedName = _sqlGenerationHelper.GenerateParameterName(parameterName);

                    substitutions.Add(substitutedName);
                    relationalCommandBuilder.AddParameter(parameterName, substitutedName);
                    parameterValues.Add(parameterName, parameter);
                }
            }

            // ReSharper disable once CoVariantArrayConversion
            sql = string.Format(sql, substitutions.ToArray());

            return new RawSqlCommand(
                relationalCommandBuilder.Append(sql).Build(),
                parameterValues);
        }
    }

  从上面这段代码可以看到,它是在sql = string.Format(sql, substitutions.ToArray()); 部分报错,这里做格式化,而我们的SQL语句中有花括号,自然就会报错了!

  怎么解决,有三个方法。

  1、使用string.Replace 替换掉花括号,因为string.Format会将花括号当做替换的参数,比如:{0}  {1} ,所以,我们要保留原有的花括号,可以对整个SQL语句执行以下替换,将SQL语句中的单花括号替换成两个花括号,两个花括号会在string.Format的时候转义成一个,比如:

    var sql = "INSERT INTO test(name,age,remark)VALUES('zhangsan',20,'remark:{ age is 20}')";
    sql = sql.Replace("{", "{{").Replace("}", "}}");
    var result = await dbContext.Database.ExecuteSqlRawAsync(sql);

  2、使用参数化来实现,比如:

    var connection = dbContext.Database.GetDbConnection();
    var factory = DbProviderFactories.GetFactory(connection);

    var nameParameter = factory.CreateParameter();
    nameParameter.ParameterName = "name";
    nameParameter.Value = "zhangsan";

    var ageParameter = factory.CreateParameter();
    ageParameter.ParameterName = "age";
    ageParameter.Value = 20;

    var remarkParameter = factory.CreateParameter();
    remarkParameter.ParameterName = "remark";
    remarkParameter.Value = "remark:{ age is 20 }";

    var sql = "INSERT INTO test(name,age,remark)VALUES(@name,@age,@remark)";
    var result = await dbContext.Database.ExecuteSqlRawAsync(sql);

   3、直接使用格式化,其实从上面的代码上看,本质上也是参数化,我们想想Microsoft.EntityFrameworkCore.Storage.Internal.RawSqlCommandBuilderBuild 方法为什么要做一个格式化?不就是给我们自定义格式化SQL使用的么,我们可以这么做:  

    var sql = "INSERT INTO test(name,age,remark)VALUES('{0}',{1},'{2}')";
    var result = await dbContext.Database.ExecuteSqlRawAsync(sql, "zhangsan", 20, "remark:{age is 20}");

  

  总结

  其实,这个就是花括号导致的问题,但是我们不能说保存到数据库的字符串里面不能存在花括号,比如我们输入的文本、数学表达式、代码、JSON格式化的数据等都有可能出现花括号需要保存到数据库中。总之,知道为什么报错就好了,其实开发的时候尽量避免,无论哪种解决方法,都可以根据自己的情况定,是在不行,可以自行使用ADO.NET的方式来实现。

   

标签:remark,string,自定义,format,age,SQL,EFCore,sql,var
From: https://www.cnblogs.com/shanfeng1000/p/18328616

相关文章

  • C自定义类型(结构体,联合体,枚举)详解
            在C语言中,数据类型可以分为内置类型(charshortintlongfloatdouble...)和自定义类型。内置类型是由编程语言本身定义的基本数据类型,而自定义类型是由程序员根据需要创建的数据类型。    自定义类型:  结构体,联合体(共用体),枚举。结构体:用于组......
  • WPF【无限滚动图片浏览】自定义控件
    自定义控件自定义控件是我比较陌生的一个主题。我好久没练习过wpf了,需要巩固记忆。我想了一会儿,打开动漫之家,忽然觉得这个看漫画的图片浏览控件有意思。于是特地花了一天做了这个图片控件。我原本以为很容易,但实际上并不简单。这个图片浏览控件比我想象中要难许多,有技术上的难题......
  • C++自定义接口类设计器之模板代码生成四
    关键代码QStringListmultis=templateStr.split('\n');boolstartConfig=false;boolstartVar=false;boolstartTemplate=false;for(constauto&line:multis){if(startConfig){if(line.trimmed().st......
  • [Spring]自定义注解
    SpringBoot自定义注解实现在学习SpringBoot过程中,学习了一些SpringBoot特有的注解,大多是为了使用方便将多个注解进行了整合。既然学习到了注解,就来重新认识一下Spring的自定义注解实现过程,在之后学习新注解的实现原理时会更加游刃有余。SpringBoot实现自定义注解Java元注解Jav......
  • Java中的类加载机制与自定义类加载器设计
    Java中的类加载机制与自定义类加载器设计大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨Java中的类加载机制与自定义类加载器设计。Java的类加载机制是Java虚拟机(JVM)运行时系统的基础之一,了解其工作原理以及如何设计自定义类加载器,对......
  • 如何将 f 字符串转换为 .format()?
    我有这个函数,它使用f字符串来打印许多变量:defmyfunc(*args,**kwargs):if'fruit'and'juice'inkwargs:print(f"Ilike{'and'.join(args)}andmyfavoritefruitis{kwargs['fruit']}")print(f"M......
  • PyTorch 训练自定义功能齐全的神经网络模型的详细教程
    在前面的文章中,老牛同学介绍了不少大语言模型的部署、推理和微调,也通过大模型演示了我们的日常的工作需求场景。我们通过大语言模型,实实在在的感受到了它强大的功能,同时也从中受益颇多。今天,老牛同学想和大家一起来训练一个自定义的、但是功能齐全的简单的神经网络模型。这个模型......
  • 易优CMS模板标签screening文档筛选指定自定义字段读取筛选条件
    [基础用法]标签:screening描述:用于在列表页文档筛选场景(支持文章、产品、视频、图集以及自定义等模型)用法:{eyou:screeningid='field'currentclass='active'alltxt='不限'}<divclass="row"><divclass="filter-box"><......
  • C语言自定义类型结构体与位段超详解
    文章目录1.结构体类型的声明1.1结构体声明1.2结构体变量的创建和初始化1.3结构体的特殊声明1.3结构体的自引用2.结构体内存对齐2.1对齐规则2.2为什么存在内存对齐2.3修改默认对齐数3.结构体传参4.结构体实现位段4.1什么是位段4.2位段成员的内存......
  • mybatis-plus 自定义sql拼接 的方式进行Wrapper条件查询 实现了分页 多表查询
    法一:用单表的思想(可以跳过,直接看法二)方法:先收集公共字段到集合中,再批量查询,然后封装起来缺点:相较于法二,代码量大,多访问了一次数据库service层:@Service@RequiredArgsConstructorpublicclassProductServiceImplextendsServiceImpl<ProductMapper,Product>implements......