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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM