EntityFramework 7 Join Count LongCount 奇怪问题

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介:

BloggingContext 配置代码:

using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Metadata;
using System.Collections.Generic;

namespace EF7
{
    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<BlogCate> BlogCates { get; set; }

        protected override void OnConfiguring(DbContextOptions builder)
        {
            builder.UseSqlServer(@"Server=.;Database=Blogging;Trusted_Connection=True;");
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<Blog>()
                .Key(b => b.BlogId);
            builder.Entity<BlogCate>()
                .Key(b => b.CateId);
        }
    }

    public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
        public int BlogCateId { get; set; }
    }
    public class BlogCate
    {
        public int CateId { get; set; }
        public string CateName { get; set; }
    }
}

BloggingContext 的配置很简单,只有 Blog 和 BlogCate 两个实体,注意我在 OnModelCreating 映射配置的时候,并没有使用 OneToMany 进行外键映射配置,测试代码:

[Fact]
public void ConutTestNoJoin()
{
    using (var context = new BloggingContext())
    {
        var query = from b in context.Blogs
                    select b;
        var countLog = query.LongCount();
        var count = query.Count();
    }
}

测试结果:

SQL Server Profiler 捕获 SQL 代码:

exec sp_executesql N'SELECT COUNT(*)
FROM [Blog] AS [b]
WHERE [b].[Url] = @p0',N'@p0 nvarchar(23)',@p0=N'http://www.cnblogs.com/'

注意 Blogs 表中时没有任何数据的,上面测试代码简单的不能再简单了,当然测试结果没什么问题,生成 SQL 代码也是我们想要的格式(COUNT(*)),这种查询时我们一般常用的 Linq 查询方式,也就是查询单个实体集的 Count,还有一种场景是使用 join 关联,然后进行 Where 条件限制,主要是对主表的限制,然后查询主表符合条件的个数,这种场景我们应该使用 Linq 查询时候也会经常遇到,比如下面测试代码:

[Fact]
public void ConutTestWithJoin()
{
    using (var context = new BloggingContext())
    {
        var query = from b in context.Blogs
                    join c in context.BlogCates on b.BlogCateId equals c.CateId
                    where b.Url.Equals("http://www.cnblogs.com/") && c.CateName.Equals("ef7")
                    select b;
        var countLog = query.LongCount();
        var count = query.Count();
    }
}

上面测试代码中,我对 BlogCates 中的 CateName 进行了“ef7”的条件限制,测试结果:

详细异常信息:

Expression of type 'System.Data.Common.DbDataReader' cannot be used for parameter of type 'Microsoft.Data.Entity.Query.QuerySourceScope' of method 'Microsoft.Data.Entity.Query.QuerySourceScope`1[Microsoft.Data.Entity.Metadata.IValueReader] CreateValueReader(Remotion.Linq.Clauses.IQuerySource, Microsoft.Data.Entity.Query.QueryContext, Microsoft.Data.Entity.Query.QuerySourceScope, System.Data.Common.DbDataReader)'

SQL Server Profiler 捕获 LongCount 生成的 SQL 代码:

exec sp_executesql N'SELECT [b].[BlogCateId], [b].[BlogId], [b].[Url]
FROM [Blog] AS [b]
INNER JOIN [BlogCate] AS [c] ON [b].[BlogCateId] = [c].[CateId]
WHERE ([b].[Url] = @p0 AND [c].[CateName] = @p1)',N'@p0 nvarchar(23),@p1 nvarchar(3)',@p0=N'http://www.cnblogs.com/',@p1=N'ef7'

LongCount 生成的这段 SQL,你如果仔细观察的话,其实也有问题,我们使用 Linq 明明写的是 LongCount 语句,生成的 SQL 代码应该和我们第一个测试代码生成的一样,也就是 COUNT(*),有可能你认为是 SQL Server Profiler 捕获 SQL 代码问题,你也可以使用 EF7 自己提供的 SQL 代码纪录方式:EntityFramework 7 如何查看执行的 SQL 代码?,测试之后,你会发现:生成的 SQL 和 SQL Server Profiler 是一样的,之前遇到的 short 类型字段生成也是这样,当然我个人觉得可能还有一些其他的 Linq 语句不能被“翻译”,只是现在还未发现而已,捕获生成的 SQL 代码,EF7 确实需要完善下,如果你使用 EF7 觉得这些语句“不安全”的话,你可以只看测试结果就行了,毕竟生成 SQL 只是作为参考,测试结果才是最准确的。

回到 Count 报错问题上来,这个问题也花了我一些时间,我一开始认为是 join 关联实体 where 条件的问题,然后我把 join 的 where 条件去掉,发现还是会报错,异常提示大概是说参数类型的问题,具体我也不知道是哪边的问题,反正异常提示信息就这么多。而使用 LongCount 是我无意间发现的,因为之前我们获取数量都是使用的 Count 语句,反正我是不知道有个 LongCount,使用 query. 下拉看可以访问到东西的时候,就无意间发现还有个 LongCount,然后没抱希望的试了下,居然可以???然后我就很奇怪,我查询出来的结果集数量总共不到几百,远远还没达到 Long 的级别,然后新建测试项目,最后发现还是会出现这个问题,这边只能纪录一下这个“奇怪”的问题。

对于我来说,好消息是:开发项目中可以使用 LongCount,来避免 Count 报错问题,但总感觉心里不踏实,这种 join where 条件限制来获取 Count 的方式,我们应该会经常用到,如果你看出是哪方面问题了,还请指教,感谢!


本文转自田园里的蟋蟀博客园博客,原文链接:http://www.cnblogs.com/xishuai/p/ef7-linq-join-count-longcount-error.html,如需转载请自行联系原作者

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
相关文章
|
10月前
|
监控 Go
博客园 ☜ golang select 的 case 执行顺序
Go 语言的 `select` 语句用于等待多个通道操作就绪。当非阻塞的 chan1, chan2, chan3 同时可读时,`select` 会随机选择一个执行,之后的循环中其他未选中的 case 仍有执行机会。如果所有 case 都未准备好,将执行 default case。
|
11月前
|
开发框架 .NET C#
C#学习相关系列之Linq用法---group和join相关用法(三)
C#学习相关系列之Linq用法---group和join相关用法(三)
352 1
|
11月前
|
SQL Java
一直傻傻分不清 count(*) count(id) count(1) 这次终于整明白了
一直傻傻分不清 count(*) count(id) count(1) 这次终于整明白了
117 0
|
XML SQL Java
如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)
如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)
如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)
|
SQL Java 程序员
记录:1221 - Incorrect usage of UNION and ORDER BY...【亲测有效】
记录:1221 - Incorrect usage of UNION and ORDER BY...【亲测有效】
489 0
|
SQL 数据库
left join 后用 on 还是 where,区别大了!
前天写SQL时本想通过 A left B join on and 后面的条件来使查出的两条记录变成一条,奈何发现还是有两条。 后来发现 join on and 不会过滤结果记录条数,只会根据and后的条件是否显示 B表的记录,A表的记录一定会显示。 不管and 后面的是A.id=1还是B.id=1,都显示出A表中所有的记录,并关联显示B中对应A表中id为1的记录或者B表中id为1的记录。
151 0
left join 后用 on 还是 where,区别大了!