[.NET] EF LINQ 按时间对数据分类汇总

========================================================

作者:qiujuer

博客:blog.csdn.net/qiujuer网站:www.qiujuer.net开源库:Genius-Android转载请注明出处:http://blog.csdn.net/qiujuer/article/details/41868331========================================================

发现国内弄 MvcWebAPI 的人简直少的可怜啊;前段时间发了大量的
WebAPI
的相关博文看的人不多;可以说是无人问津。

在对数据的操作中,对一堆数据的分类汇总是比较常见的,特别是按照时间进行分类汇总。比如算出某一天,某一月的数据总量等等。而鉴于国内研究的人少所以遇到一些问题简直没法查询,其中就包括:

<ExceptionMessage>
LINQ to Entities 不识别方法“System.String ToString(System.String)”,因此该方法无法转换为存储表达式。
</ExceptionMessage>

现在我有一堆存储在数据库中的数据;其数据简单格式如下:

    public class DataModel
    {
        public int Id { get; set; }
        public string Data { get; set; }
        public DateTime Time { get; set; }
    }

就只有一个数据,一个时间,一个标志字段。

现在这样的数据有一大堆,各个时间段的都有;我想要统计分别每天有哪些数据存在。

方案一

最傻,最直接;第一种方法你首先查询该数据库中所有数据;然后使用for 或者
foreach 循环遍历整个数据,然后判断加入到不同的 List 列表中,然后打包返回。

该方法未使用 LINQ,而是使用的简单的操作来实现;这里就不贴出代码了。

方案二

思路清晰。在这中方法中在进行SQL 查询时就把返回的时间 改成 “天” ,而没有时间的格式;然后再进行分类汇总,最后返回想要的字段。

            var note2 = db.Notes
                // 先进行了时间字段变更为String字段,切只保留到天
                .Select(n => new { Data = n.Data, Time = n.Time.ToString("yyyy-MM-dd") })
                // 分类
                .GroupBy(n => n.Time)
                // 返回汇总样式
                .Select(n => new { Time = n.Key, Datas = n.ToList() }).ToList();

方法似乎很正确,但是运行后:

<Error>
<Message>出现错误。</Message>
<ExceptionMessage>
LINQ to Entities 不识别方法“System.String ToString(System.String)”,因此该方法无法转换为存储表达式。
</ExceptionMessage>
<ExceptionType>System.NotSupportedException</ExceptionType>
<StackTrace>...</StackTrace>
</Error>

这时就出现了这样的情况,是我们的思路错了?不是,思路完全正确。只是在 EF 中的 LINQ 不能识别 ToString 而已。

方案三

思路不变,任然才有方案二的思路,以及大部分代码,只更改一小部分。

            var note3 = db.Notes
                // 先进行了时间字段变更为String字段,切只保留到天
                // 采用拼接的方式
                .Select(n => new { Data = n.Data, Time = n.Time.Year + "-" + n.Time.Month + "-" + n.Time.Day })
                // 分类
                .GroupBy(n => n.Time)
                // 返回汇总样式
                .Select(n => new { Time = n.Key, Datas = n.ToList() }).ToList();

既然不能返回,那我们就来自己拼接;这种方式能够正确执行并返回正确数据。推荐!!!

方案四

换个思路,既然EF LINQ
中无法使用 ToString ,那么单独的 LINQ 呢?

            // 先进行数据查询,返回数据
            var datas = await db.Notes.ToListAsync();
            // 然后在内存中使用 LINQ
            var note4 = datas.Select(n => new { Data = n.Data, Time = n.Time.ToString("yyyy-MM-dd") })
                .GroupBy(n => n.Time)
                .Select(n => new { Time = n.Key, Datas = n.ToList() }).ToList();

至于分类汇总的思路不变;只是把ToString 放到了独立的
LINQ 中使用而已;实践证明,这个是可行的方案。同样推荐!!!

区别是啥?

第二种思路无法成功,主要是 EF 识别不了 ToString 中的操作,这个很好理解,因为EF 最终是需要换成
SQL 语句进行执行的。如果我们加上了 ToString 看似可以,但是其实完全不合理,因为电脑不知道我们 ToString 中究竟有些啥,所以它不知道应该转换为什么样的 SQL 语句。

所以我们在 方案三中直接告诉了他,就是使用时间字段的对应参数进行组装,所以他能正确执行。

至于 方案四 这个就更加好说了,因为ToString 是放在查询后,所以它无需进行对应的
SQL 语句的操作了,所以这个时候随你怎么弄都不为过。

方案三与方案四 结果完全一样,代码也几乎一样;但是其执行上却相差甚远!

为何?

  • 因为 方案三 基本上是把所有的工作放在了 SQL 上执行,这边只负责接收成果就OK 了!
  • 而 方案四 则是获取数据是在 SQL 操作,但是数据的处理是放在服务器端内存中进行的!

其优劣性

  • 如果你的 SQL 数据性能远远大于 你的服务器后台 配置,那么才有第三方案 是比较划算的。
  • 如果你的 服务器的内存不错,分析也不错;能完全胜任其数据处理的话 第四方案 是你的不二选择。

这个其处理的时间就不太好估计了,毕竟每个人的电脑都不尽相同;所以看个人估计吧!一般情况下两种都差距不大。至于没有说第一种,因为第一种的性能上有待考虑;当然如果你的分析算法够OK 的话,那就可以与 第四方案 拼个你死我活。

实际使用

<ArrayOfNoteInfo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/GeniusSpace.Controllers.Api">
<NoteInfo>
<Changes>
<SNote>
<Content>似的撒旦</Content>
<Time>2014-12-11</Time>
</SNote>
<SNote>
<Content>sewrwfqf</Content>
<Time>2014-12-11</Time>
</SNote>
<SNote>
<Content>sgewhsdwqd</Content>
<Time>2014-12-11</Time>
</SNote>
</Changes>
<Time>2014-12-11</Time>
</NoteInfo>
<NoteInfo>
<Changes>
<SNote>
<Content>asgafasgre</Content>
<Time>2014-12-10</Time>
</SNote>
<SNote>
<Content>dgwetwet</Content>
<Time>2014-12-10</Time>
</SNote>
</Changes>
<Time>2014-12-10</Time>
</NoteInfo>
<NoteInfo>
<Changes>
<SNote>
<Content>rwqyhtrjhdf</Content>
<Time>2014-12-09</Time>
</SNote>
</Changes>
<Time>2014-12-09</Time>
</NoteInfo>
</ArrayOfNoteInfo>

这是我这边使用的情况,当然其参数与上面的参数不对;但是其分类汇总是完成了的。

采用的是 第三方案 ,其
SQL 语句如下:

SELECT
    [Project2].[C2] AS [C1],
    [Project2].[C1] AS [C2],
    [Project2].[C4] AS [C3],
    [Project2].[Content] AS [Content],
    [Project2].[C3] AS [C4]
    FROM ( SELECT
        [Distinct1].[C1] AS [C1],
        1 AS [C2],
        [Extent2].[Content] AS [Content],
        CASE WHEN ([Extent2].[Content] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE CASE WHEN (DATEPART (year, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (year, [Extent2].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (month, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (month, [Extent2].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (day, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (day, [Extent2].[Published]) AS nvarchar(max)) END END AS [C3],
        CASE WHEN ([Extent2].[Content] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C4]
        FROM   (SELECT DISTINCT
            CASE WHEN (DATEPART (year, [Extent1].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (year, [Extent1].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (month, [Extent1].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (month, [Extent1].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (day, [Extent1].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (day, [Extent1].[Published]) AS nvarchar(max)) END AS [C1]
            FROM [dbo].[Notes] AS [Extent1] ) AS [Distinct1]
        LEFT OUTER JOIN [dbo].[Notes] AS [Extent2] ON ([Distinct1].[C1] = (CASE WHEN (DATEPART (year, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (year, [Extent2].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (month, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (month, [Extent2].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (day, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (day, [Extent2].[Published]) AS nvarchar(max)) END)) OR (([Distinct1].[C1] IS NULL) AND (CASE WHEN (DATEPART (year, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (year, [Extent2].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (month, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (month, [Extent2].[Published]) AS nvarchar(max)) END + N'-' + CASE WHEN (DATEPART (day, [Extent2].[Published]) IS NULL) THEN N'' ELSE  CAST( DATEPART (day, [Extent2].[Published]) AS nvarchar(max)) END IS NULL))
    )  AS [Project2]
    ORDER BY [Project2].[C1] ASC, [Project2].[C4] ASC

从语句可以看出,其分类汇总,以及查询全部都是在SQL端完成。

按天分类实现了,按月、按年、按小时那还用说么?

如果你有更好的思路,还希望能写在下面一起交流交流。

========================================================

作者:qiujuer

博客:blog.csdn.net/qiujuer网站:www.qiujuer.net开源库:Genius-Android转载请注明出处:http://blog.csdn.net/qiujuer/article/details/41868331========================================================

时间: 2024-08-25 09:34:19

[.NET] EF LINQ 按时间对数据分类汇总的相关文章

ef linq select where dynamic singleordefault

singleordefault(where) 条件不支持动态 所以想要达到目标,就需要转换思路,把where在前面调用,然后再接,代码如下 public TResult GetSingle<T, TResult>(Expression<Func<T, bool>> exWhere, Expression<Func<T, TResult>> selector) where T : class { using (SysDb<T> db =

Java实现时间动态显示方法汇总

这篇文章主要介绍了Java实现时间动态显示方法汇总,很实用的功能,需要的朋友可以参考下 本文所述实例可以实现Java在界面上动态的显示时间.具体实现方法汇总如下: 1.方法一 用TimerTask: 利用java.util.Timer和java.util.TimerTask来做动态更新,毕竟每次更新可以看作是计时1秒发生一次.代码如下: import java.awt.Dimension; import java.text.SimpleDateFormat; import java.util.C

Excel数据分类汇总与数据透视表

苏轼的<题西林壁>:横看成岭侧成峰,远近高低各不同.给我们讲述着一个道理:同样的事物与内容,从不同角度观察会得到意想不到的结果.同样,Excel不单单只是一个数据的记录工具,也不单单是一个表格的制作工具,学会怎么从一行一行单调的数据去挖掘出我们想要的信息也是它的一个强项.我们不应小看Excel的挖掘功能,使用好挖掘功能会让我们得到意想不到的效果,将是我们工作中分析问题的一大助力. 下面介绍两种常用的数据分析.挖掘工具:数据分类汇总与数据透视表.要使用的示例数据如下: 呵呵-有点偷懒,还是使用上

SQLServer---使用Case When解决SQLServer数据分类汇总问题

SQLServer---使用Case When解决SQLServer数据分类汇总问题 近半年一直在负责某市的人事档案管理系统的后期开发和维护工作,之前客户给了一张如下图的表格,需要我去汇总数据,然后填充到表格中. 具体的需求:统计出每一个工作人员在某一段时间内分别打印了多少张不同的信函(或报表). 最初的想法 1.  查出使用该系统的工作人员 select realName as '姓名' from T_User where userID in(select distinct userID fr

在写EF 时把时间格式化的做法

SELECT COUNT(l.LogSeq), date_format(l.CreateDate,'%Y-%m') CreateDateByMonth FROM LOL l WHERE l.CreateDate>='2017-1-1' AND l.CreateDate<='2017-8-16' GROUP BY CreateDateByMonth 把数据按照月份分组获取所需要的数据SQL语句变为EF,错误的写法: //先做基本查询 var querySql = from l in LOL se

ASP.NET EF(LINQ/Lambda查询)

EF(EntityFrameWork) ORM(对象关系映射框架/数据持久化框架),根据实体对象操作数据表中数据的一种面向对象的操作框架,底层也是调用ADO.NET ASP.NET MVC 项目会自动导入MVC程序集,因为默认.NET环境(GAC)中没有这个程序集 1 create database MyFirstEF 2 on primary 3 ( 4 name='MyFirstEF.mdf', 5 --修改为自己电脑上SQL DB路径 6 filename='E:\ProgramMSSQL

ASP.NET MVC4.0+EF+LINQ+EasyUI+网站+角色权限管理系统(1)

本系列的的角色权限管理主要采用Dotnet MVC4工程内置的权限管理模块Simplemembership实现,主要有关文件是InitializeSimpleMembershipAttribute.cs和AccountModels.cs 下面是对这两个文件的了解和改造 WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", &qu

EF+LINQ事物处理

在使用EF的情况下,可能也会存在说我有多个站点,同时去访问一个数据库,操作同一条数据的同一个值,那么我们怎么来进行事物的处理呢 有这么一个很好的解决方式 EF6里面提供了这么一个方式来处理事物 Database.BeginTransaction() : 为用户提供一种简单易用的方案,在dbEntitys 中启动并完成一个事务 -- 合并一系列操作到该事务中.同时使用户更方便的指定事务隔离级别. Database.UseTransaction() : 允许DbContext使用一个EF框架外的事务

一个简单的EF Linq MVC Web应用程序

LINQ(Language Integrated Query)语言集成查询是一组用于c#和Visual Basic语言的扩展. 它允许编写C#或者Visual Basic代码以操作内存数据的方式,查询数据库. LINQ的读法:lin k 很多人会误读为lin Q LINQ的全称:Language-Integrated Query LINQ的关键词:from, select, in, where, group by, orderby, … 详情请查阅:https://baike.so.com/do