【问题标题】:C# Entity Framework text SQL query wrapperC# Entity Framework 文本 SQL 查询包装器
【发布时间】:2017-10-20 17:30:37
【问题描述】:

我有一个类似的问题: How to retrieve multiple columns from non-entity type sql query?

我需要实现方法string[,] DirectQuery(string sqlText, string[] param),它基本上是 SQL Server Management Studio 的 C# 等效项。

用户应该以字符串文本的形式输入 SQL 查询(+ 字符串参数以避免 SQL 注入)并接收回包含查询结果的字符串矩阵。

在内部,我使用的是实体框架。

这是我的实现:

public string[,] DirectQuery(string sqlQuery, string[] param)
{
        //discover how many fields are specified in the select clause
        string ip = sqlQuery.ToLower().Split(new string[] { "from" }, StringSplitOptions.None)[0];
        int cols = ip.Count(y => y == ',') + 1;

        //execute the query
        DbRawSqlQuery<string> res = param != null ? _context.Database.SqlQuery<string>(sqlQuery, param) : _context.Database.SqlQuery<string>(sqlQuery);

        //wrap everything in a matrix to return
        return res.ToArray().Array2Matrix(res.ToArray().Length /cols, cols);
    }

在哪里

public static T[,] Array2Matrix<T>(this T[] flat, int rows, int cols) where T : class

是我将平面数组转换为rows x cols 矩阵的自定义方法。

如果用户在 select 子句中指定了一个属性,那可以正常工作,但如果需要 2+ 个字段,则执行 DirectQuery 会触发运行时异常 dbrawsqlquery he data reader has more than one field. Multiple fields are not valid for EDM primitive or enumeration types。这是完全合理的,但由于查询可以是我无法创建自定义类来包装所有可能结果的任何内容。

你有什么建议?

【问题讨论】:

  • 如果您真的希望允许用户输入原始 SQL 查询然后代表他们执行它们,EF 可能不是适合这个。您应该查看像 Dapper.NET(例如,它为该网站提供支持)之类的东西,它可以轻松地执行原始 SQL 并将结果转换为漂亮的 .NET 对象以供使用
  • 非常感谢,它运行良好。但是我仍然遇到一些参数问题。用户在他们的查询中指定一定数量的参数,按照他们喜欢的方式命名它们(@p0、@customerId、@foo、...),并在字符串[]中传递它们各自的值。如果我将参数 string[] 直接传递给 Query 方法,Dapper 会触发异常;相反,它需要像new { p0 = "17R13DT_GP_02_MP2", ... } 这样的结构。有没有更紧凑的方法?

标签: c# sql-server entity-framework-6


【解决方案1】:

问题是您正在使用一种方法 - DbRawSqlQuery 必须告诉它期望什么类型,而您告诉它只期望一个字符串,所以它不知道如何处理多个返回列。

如果您指定string[]IEnumerable&lt;string&gt; 或其他内容,也许它会起作用?或者,您可以定义一系列具有 1、2、3、4 等值的对象,并在运行时检测项目的数量并使用正确的类......但这似乎很荒谬。

真的,我建议不要像上面有人建议的那样使用 EF。找到可以返回动态对象的东西,或者直接使用 ADO.Net。

【讨论】:

  • 是否可以使用反射创建具有 1、2、3、4 等值的运行时对象?
  • 可能吗?也许。但是通过在运行时创建类型,您只能在运行时访问属性,因此您基本上会丢弃任何编译时类型检查能力......您基本上创建的是一个数组/list/table 类型的东西使用反射来访问其成员,因此与仅使用数组相比,无疑会非常效率低下。我真的不会尝试重新发明轮子 - 只需使用已经存在的类型并直接访问 ADO.Net 并使用 DataTable。
猜你喜欢
  • 2021-07-12
  • 1970-01-01
  • 2011-02-22
  • 2019-03-04
  • 2017-10-23
  • 2016-09-19
  • 1970-01-01
  • 2021-05-18
  • 2021-01-08
相关资源
最近更新 更多