【问题标题】:Converting Stored Procedure PIVOT table to LINQ query将存储过程 PIVOT 表转换为 LINQ 查询
【发布时间】:2015-09-15 11:57:46
【问题描述】:

我的想法是转换我之前定义的当前存储过程。目的是,我不能使用存储过程从数据库中返回数据。这样做的原因是留在查询中。我需要将现有表转换为数据透视表,之后我必须通过 ASP.NET WebAPI 返回数据。此数据透视表是动态的,这意味着当用户添加新文章时,它将作为列添加到数据透视表中。

普通表如下所示:

datum      | rate     | article
--------------------------------
2013-01-03 |  97,766..|  DE011
2013-01-05 |  90.214..|  DE090
2013-01-10 |  97,890..|  DE011
2013-01-13 |  65,023..|  DE220
2013-01-13 |  97,012..|  DE300
2013-01-15 |  97,344..|  DE300
....

数据透视表应如下所示:

rate | DE011 | ... | DE090 | ... | DE220 | ... | DE300
-------------------------------------------------------
100  |   0   | ... |   1   | ... |   0   | ... |   0
 98  |   2   | ... |   0   | ... |   1   | ... |   0
 97  |   0   | ... |   0   | ... |   0   | ... |   2
 90  |   0   | ... |   1   | ... |   0   | ... |   4
...

datum 列对于数据透视表很重要,因为用户必须在角度视图中进行一些输入。在此示例中,用户选择dateFromdateTo 输入。汇率将四舍五入您在数据透视列rate 中看到的数字。文章描述位于新表格列标题中,每篇文章的汇率都会计算在内。

我的存储过程在 SQL Server 中运行良好。但是在将 SP 导入 EDM 模型后,实体框架定义了一个返回类型 INT,这对我的目的来说是不可能的。

这是EF的代码:

 public virtual int getMonthIsin(Nullable<System.DateTime> fromDate, Nullable<System.DateTime> toDate)
        {
            var fromDateParameter = fromDate.HasValue ?
                new ObjectParameter("fromDate", fromDate) :
                new ObjectParameter("fromDate", typeof(System.DateTime));

            var toDateParameter = toDate.HasValue ?
                new ObjectParameter("toDate", toDate) :
                new ObjectParameter("toDate", typeof(System.DateTime));

            return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("getMonthIsin", fromDateParameter, toDateParameter);
        }

我还在我的 WebAPI-Controller 中尝试了 .SqlQuery(),如下所示:

return db.Database.SqlQuery<IQueryable>("EXEC getMonthIsin @fromDate, @toDate", fromDate, toDate).AsQueryable();

但它不起作用。

好吧,现在的想法是尝试 LINQ 查询并获取返回值。我没有任何想法来实现这个:(

目前我已经大致尝试了这个 LINQ 查询:

public IQueryable getDatas(DateTime fromDate, DateTime toDate)
{
   var query = from t in db.table1
               where t.datum >= fromDate && t.datum <= toDate
               group t by t.article
                 into grp
                 select new
                 {
                    articles = grp.Key,
                    rate = grp.Select(g => g.rate),
                    total = grp.Select(g => g.rate).AsQueryable()
                 };

   return query;
}

但这并不是真正的正确回报。如果有人可以帮助我,那将非常有帮助!我会为每个好的答案投票!

【问题讨论】:

  • 您永远无法将动态 PIVOT 语句的输出捕获到静态 EF 类型中。使用像 Dapper 这样的东西。
  • @GertArnold 你有什么例子可以看吗?如何用 LINQ 定义它?
  • @GertArnold 你知道如何用 Dapper Dot Net 实现上面的 pivot 例子吗?
  • @RoopeshShenoy 你对我的问题有什么想法吗?

标签: c# linq stored-procedures asp.net-web-api entity-framework-6


【解决方案1】:

实体框架不适合获取动态数据结构。 Dapper 是这里使用的工具。它基本上是IDbConnection上的扩展方法的集合,其中一个是Query,它返回一个IEnumerable&lt;dynamic&gt;,其中dynamic是一个实现IDictionary&lt;string, object&gt;的对象。获取数据非常简单:

IEnumerable<IDictionary<string, object>> result;

using (var cnn = new SqlConnection(connectionString))
{
    cnn.Open();

    var p = new DynamicParameters();
    p.Add(" @fromDate", fromDate, DbType.DateTime);
    p.Add(" @toDate", toDate, DbType.DateTime);

    result = (IEnumerable<IDictionary<string, object>>)
                cnn.Query(sql: "getMonthIsin", 
                          param: p, 
                          commandType: CommandType.StoredProcedure);
}

现在您有一个IEnumerable&lt;IDictionary&lt;string, object&gt;&gt;,其中一项 (IDictionary&lt;string, object&gt;) 代表存储过程结果集中的一行键/值对:

Key    Value
-----  ----
rate   100
DE011  0
...    ...
DE090  1
...    ...
DE220  0
...    ...
DE300  0

如何从这里出发由您决定。例如,您可以将结果转换为DataTable,如下所示:Dictionary<string, object> to DataTable

顺便说一句,Dapper 不仅简单,而且速度也非常快。

【讨论】:

  • 我必须在哪里添加上面的代码?我是否需要 using 语句,因为我的连接在 Controller 中定义如下:private TestContext db = new TestContext(); 并且在从 EF 生成的 Context.cs 中定义了到存储过程 public partial class TestContext : DbContext { public TestContext() : base("name=TestContext") { }... 的所有连接
  • 您可以在不参考 EF 的情况下执行此操作。只需从配置文件中获取连接字符串并创建自己的 SqlConnection 实例。
  • 也就是说我可以直接在控制器中添加代码?
  • 要从客户端访问存储过程,我将控制器 public class QR_DS022Controller : ApiController {...} 与所有 GET 请求一起使用。在这个控制器中,我无法定义 using(...) 等等。抱歉这个愚蠢的问题,但您知道我如何在控制器中定义您的示例以从我的客户端访问查询吗?
  • 我已经用你的例子解决了我的问题!非常好!
猜你喜欢
  • 2013-10-22
  • 2023-04-08
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
  • 2014-06-10
  • 1970-01-01
  • 2019-09-14
相关资源
最近更新 更多