zoukankan      html  css  js  c++  java
  • EntityFramework 7 Join Count LongCount 奇怪问题

    先吐槽一下,EF7 目前来说,真对的起现在的版本命名:"EntityFramework": "7.0.0-beta1"。

    这篇博文纪录一下:当 Linq 查询中使用 Join 语句,然后获取 Count 的时候会报错,而使用 LongCount 却没有任何问题。

    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 的方式,我们应该会经常用到,如果你看出是哪方面问题了,还请指教,感谢!


    已提交至 EntityFramework 7 issues:Use EF7, Linq Join Count is error

  • 相关阅读:
    使用 Dockerfile 定制镜像
    UVA 10298 Power Strings 字符串的幂(KMP,最小循环节)
    UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)
    LeetCode Best Time to Buy and Sell Stock 买卖股票的最佳时机 (DP)
    LeetCode Number of Islands 岛的数量(DFS,BFS)
    LeetCode Triangle 三角形(最短路)
    LeetCode Swap Nodes in Pairs 交换结点对(单链表)
    LeetCode Find Minimum in Rotated Sorted Array 旋转序列找最小值(二分查找)
    HDU 5312 Sequence (规律题)
    LeetCode Letter Combinations of a Phone Number 电话号码组合
  • 原文地址:https://www.cnblogs.com/xishuai/p/ef7-linq-join-count-longcount-error.html
Copyright © 2011-2022 走看看