.net EF Core/Npgsql参数化整个where子句

.net EF Core/Npgsql参数化整个where子句,.net,postgresql,entity-framework-core,npgsql,.net,Postgresql,Entity Framework Core,Npgsql,我试图使用Entity Framework Core和Npgsql来执行原始SQL查询,其中where子句部分从数据库中拉入,实际值由用户提供。作为一个具体例子: SQL的这一部分是静态的 SELECT TITLE as TitleField, GEOM as GeomField, GEOM_X as XField, GEOM_Y as YField FROM fdw_public."MY_TABLE" 然后管理员可以在数据库中设置

我试图使用Entity Framework Core和Npgsql来执行原始SQL查询,其中where子句部分从数据库中拉入,实际值由用户提供。作为一个具体例子:

SQL的这一部分是静态的

SELECT TITLE as TitleField,
       GEOM as GeomField,
       GEOM_X as XField,
       GEOM_Y as YField
FROM fdw_public."MY_TABLE"
然后管理员可以在数据库中设置WHERE子句,例如:

COLUMNNAME LIKE '%{search}%'

这在编译时是未知的,可能是任何有效的WHERE子句

{search}部分是一个占位符。我相信来自数据库的子句,这只由应用程序所有者控制,如果他们想破坏自己的表,那没关系

最终的结果是这个SQL

SELECT TITLE as TitleField,
       GEOM as GeomField,
       GEOM_X as XField,
       GEOM_Y as YField
FROM fdw_public."MY_TABLE"
WHERE COLUMNNAME LIKE '%{search}%'
然而,{search}部分是来自web应用程序的用户输入,因此需要参数化

下面的代码可以工作,但显然对SQL注入非常开放

var sql = $@"SELECT TITLE as TitleField,
                    GEOM as GeomField,
                    XFIELD as XField,
                    YFIELD as YField
             FROM fdw_public."MY_TABLE"
             WHERE {searchDefinition.WhereClause.Replace("{search}", searchTerm)}";
            
var dbResults = _context.DatabaseSearchResults.FromSqlRaw(sql).ToList();
所以我尝试为整个where子句使用一个参数

var sql = $@"SELECT TITLE as TitleField,
                    GEOM as GeomField,
                    XFIELD as XField,
                    YFIELD as YField
             FROM fdw_public."MY_TABLE"
             WHERE @whereClause";

        var whereClauseParam = new Npgsql.NpgsqlParameter("@whereClause", searchDefinition.WhereClause.Replace("{search}", searchTerm));
        var dbResults = _context.DatabaseSearchResults.FromSqlRaw(sql,whereClauseParam).ToList();
但这会从Npgsql引发以下异常

42804:WHERE的参数必须是布尔类型,而不是文本类型

这对我来说是有意义的,因为将整个子句参数化感觉是错误的,但我想不出更好的解决方法

理想情况下,我只需要参数化搜索项,如下所示

var sql = $@"SELECT TITLE as TitleField,
                    GEOM as GeomField,
                    XFIELD as XField,
                    YFIELD as YField
             FROM fdw_public."MY_TABLE"
             WHERE {searchDefinition.WhereClause.Replace("{search}","@p0")}";

            var searchTermParam = new Npgsql.NpgsqlParameter("p0", searchTerm);
            var dbResults = _context.DatabaseSearchResults.FromSqlRaw(sql, searchTermParam).ToList();
但同样,这不起作用,这是可以理解的,因为它被逐字解释

我觉得这可能会涉及到我如何完全改变这一点,或者更糟的是,使用一些众所周知的清理方法来清理搜索字符串,但我不想这样做,我想使用参数

总之,无论哪种方式,要求都是这样

WHERE子句必须来自数据库,但可以信任 db中的WHERE子句可以是带有{search}占位符的任何有效WHERE,允许我们进行通配符之类的操作,管理员应该知道数据类型,值是否应该用引号括起来等等。 必须对搜索词进行消毒 尝试将{search}替换为{0},并将searchTerm作为参数传递给:

var sql=$@选择标题作为标题字段, GEOM作为GeomField, XFIELD作为XFIELD, 伊菲尔德 从fdw_public.MY_表 其中{searchDefinition.WhereClause.Replace{search},{0}; var dbResults=_context.DatabaseSearchResults.FromSqlRawsql,searchTerm.ToList;
为什么不让EF生成查询?如果您自己编写查询,那么使用ORM没有什么意义。DatabaseSearchResults对于域实体来说是一个非常奇怪的名称。在任何情况下,您都不能参数化整个子句。与C参数一样,参数用于传递值。应用程序的这一部分需要管理员设置WHERE子句。应用程序的其余部分使用EF生成所有必要的查询,但这是应用程序逻辑的一部分,SQL本身由其他地方控制。我不希望能够参数化整个条款,但这是我开始的概念,并试图梳理出实现我所需要的isI的最佳方式。我也接受你关于名称的观点,但在这种特殊情况下,你必须相信我,它是有意义的!这几乎是完美的。我唯一的问题是where子句包含通配符之类的内容,例如“{search}%”之类的COLUMNNAME。仅替换{search}项不能像它用单引号和通配符包装一样工作。通过删除引号并将“%”添加到参数中,它可以正常工作。我相信我可以做一些调整来处理这个问题,或者强制管理员不在占位符中包含引号/放置通配符,除非你知道更好的方法?@RobQuincey TBH我没有更好的解决方案。也许可以做点什么,但不确定。
var sql = $@"SELECT TITLE as TitleField,
                    GEOM as GeomField,
                    XFIELD as XField,
                    YFIELD as YField
             FROM fdw_public."MY_TABLE"
             WHERE {searchDefinition.WhereClause.Replace("{search}","@p0")}";

            var searchTermParam = new Npgsql.NpgsqlParameter("p0", searchTerm);
            var dbResults = _context.DatabaseSearchResults.FromSqlRaw(sql, searchTermParam).ToList();