EntityFramework 7 Left Join Where Select 奇怪问题

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

为了正确反应测试 EF7 所出现的问题,我同时也用 EF6 进行测试,测试代码都是一样的,然后使用 SQL Server Profiler 抓取 EF6、EF7 所生成的 SQL 代码。

测试环境说明:

  • EF6 版本:6.1.2-beta1
  • EF7 版本:7.0.0-beta1
  • 开发环境:VS2015 Preview
  • SQL Server Profiler 对应版本:SQL Server 2014

四种测试场景(b、c 表示对应关联实体。):

  1. where b select b
  2. no where select b
  3. where c select b
  4. no where select c

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; }
    }
}

OnModelCreating 中的映射配置代码并没有对 Blog 和 BlogCate 进行 OneToMany 关联配置,这样方便我们使用 Linq 进行 Left Join 语法编写,EF6 测试项目我使用的是 Model First,因为 EF7 测试项目中的模型更改,在 EF6 测试项目中,只要一个“Update Model from Database”命令就可以了,这样方便进行测试,当然项目中建议不要使用 Model First,EF7 的测试项目使用的是 Xunit,EF6 的测试项目直接是控制台应用程序,因为在 VS2015 中,对于非 ASP.NET 5 Class Library 项目,使用 Xunit 暂无法实现测试。下面贴一下,针对 Where Select 不同条件语法实现,EF6、EF7 所出现的具体问题?

1. where b select b

测试代码:

[Fact]
public void TestWithLeftJoin()
{
    using (var context = new BloggingContext())
    {
        var query = from b in context.Blogs
                    join c in context.BlogCates on b.BlogCateId equals c.CateId into left
                    from c in left.DefaultIfEmpty()
                    where b.Url == "http://www.cnblogs.com/"
                    select b.BlogId;
        var result = query.ToList();
    }
}

EF6 测试结果:

EF6 生成 SQL 代码:

SELECT 
    [Extent1].[BlogId] AS [BlogId]
    FROM  [dbo].[Blog] AS [Extent1]
    LEFT OUTER JOIN [dbo].[BlogCate] AS [Extent2] ON [Extent1].[BlogCateId] = [Extent2].[CateId]
    WHERE N'http://www.cnblogs.com/' = [Extent1].[Url]

EF7 测试结果:

详细异常信息:

The multi-part identifier "b.Url" could not be bound.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader()
at Microsoft.Data.Entity.Relational.Query.QueryingEnumerable1.Enumerator.MoveNext()
at System.Linq.Lookup2.CreateForJoin(IEnumerable1 source, Func2 keySelector, IEqualityComparer1 comparer)
at System.Linq.Enumerable. d__6a4.MoveNext()
at System.Linq.Enumerable. d__142.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()
at Microsoft.Data.Entity.Query.EntityQueryExecutor.EnumerableExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList [TSource] (IEnumerable1 source)
at EF7.Tests.EF7_Test.TestWithLeftJoin() in C:\Users\yuezhongxin\Desktop\EF7\src\EF7.Tests\EF7_Test.cs:line 47

2. no where select b

测试代码:

[Fact]
public void TestWithLeftJoin()
{
    using (var context = new BloggingContext())
    {
        var query = from b in context.Blogs
                    join c in context.BlogCates on b.BlogCateId equals c.CateId into left
                    from c in left.DefaultIfEmpty()
                    select b.BlogId;
        var result = query.ToList();
    }
}

EF6 测试结果:

EF6 生成 SQL 代码:

SELECT 
    [Extent1].[BlogId] AS [BlogId]
    FROM  [dbo].[Blog] AS [Extent1]
    LEFT OUTER JOIN [dbo].[BlogCate] AS [Extent2] ON [Extent1].[BlogCateId] = [Extent2].[CateId]

EF7 测试结果:

EF7 生成 SQL 代码:

SELECT [b].[BlogCateId], [b].[BlogId]
FROM [Blog] AS [b]

3. where c select b

测试代码:

[Fact]
public void TestWithLeftJoin()
{
    using (var context = new BloggingContext())
    {
        var query = from b in context.Blogs
                    join c in context.BlogCates on b.BlogCateId equals c.CateId into left
                    from c in left.DefaultIfEmpty()
                    where c.CateName == "EF7"
                    select b.BlogId;
        var result = query.ToList();
    }
}

EF6 测试结果:

EF6 生成 SQL 代码:

SELECT 
    [Extent1].[BlogId] AS [BlogId]
    FROM  [dbo].[Blog] AS [Extent1]
    INNER JOIN [dbo].[BlogCate] AS [Extent2] ON [Extent1].[BlogCateId] = [Extent2].[CateId]
    WHERE N'EF7' = [Extent2].[CateName]

EF7 测试结果:

详细异常信息:

Object reference not set to an instance of an object.
Anonymously Hosted DynamicMethods Assembly
at lambda_method(Closure , QuerySourceScope )
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()
at Microsoft.Data.Entity.Query.EntityQueryExecutor.EnumerableExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource] (IEnumerable1 source)
at EF7.Tests.EF7_Test.TestWithLeftJoinExption() in C:\Users\yuezhongxin\Desktop\EF7\src\EF7.Tests\EF7_Test.cs:line 63

4. no where select c

测试代码:

[Fact]
public void TestWithLeftJoin()
{
    using (var context = new BloggingContext())
    {
        var query = from b in context.Blogs
                    join c in context.BlogCates on b.BlogCateId equals c.CateId into left
                    from c in left.DefaultIfEmpty()
                    select c;
        var result = query.ToList();
    }
}

EF6 测试结果:

EF6 生成 SQL 代码:

SELECT 
    [Extent2].[CateId] AS [CateId], 
    [Extent2].[CateName] AS [CateName]
    FROM  [dbo].[Blog] AS [Extent1]
    LEFT OUTER JOIN [dbo].[BlogCate] AS [Extent2] ON [Extent1].[BlogCateId] = [Extent2].[CateId]

EF7 测试结果:

EF7 生成 SQL 代码:

SELECT [c].[CateId], [c].[CateName]
FROM [BlogCate] AS [c]
SELECT [b].[BlogCateId]
FROM [Blog] AS [b]

总结:

  1. where b select b(EF6 √,EF7 X)
  2. no where select b(EF6 √,EF7 √)
  3. where c select b(EF6 √,EF7 X)
  4. no where select c(EF6 √,EF7 √)

除了这几种场景,当然还有其他的比如 where b c select b 等等,但都和上面比较类似,这边就不纪录了。


本文转自田园里的蟋蟀博客园博客,原文链接:http://www.cnblogs.com/xishuai/p/ef7-linq-left-join-where-select-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
相关文章
|
4月前
|
存储 关系型数据库 MySQL
mysql中的left join、right join 、inner join的详细用法
【8月更文挑战第16天】在MySQL中,`INNER JOIN`、`LEFT JOIN`与`RIGHT JOIN`用于连接多表。`INNER JOIN`仅返回两表中匹配的行;`LEFT JOIN`保证左表所有行出现于结果中,右表无匹配时以NULL填充;`RIGHT JOIN`则相反,保证右表所有行出现于结果中。例如,查询学生及其成绩时,`INNER JOIN`仅显示有成绩的学生;`LEFT JOIN`显示所有学生及他们对应的成绩,无成绩者成绩列为空;`RIGHT JOIN`显示所有成绩及对应学生信息,无学生信息的成绩条目则为空。
161 1
|
7月前
|
SQL Oracle 关系型数据库
Oracle查询优化-left join、right join、inner join、full join和逗号的区别
【1月更文挑战第5天】【1月更文挑战第13篇】实际查询时,多表联查是常规操作,但是连接方式有多种。
659 0
|
SQL 开发框架 .NET
linq中left join和inner join的正确用法
linq中left join和inner join的正确用法
|
关系型数据库 MySQL
关于MySQL中的LEFT JOIN和LEFT OUTER JOIN的区别
LEFT JOIN是LEFT OUTER JOIN的简写版;
280 0
SQL外部联合:right outer join、left outer join、full outer join
SQL将外部联合分为了右外部联合(right outer join)、左外部联合(left outer join)、完全外部联合(full outer join)3个类型。
|
SQL 关系型数据库 MySQL
Join,left join,right join(1)--连接原理(三十九)
Join,left join,right join(1)--连接原理(三十九)
|
SQL 数据库
SQL 语句中 left join 后用 on 还是 where,区别大了!
后来发现 join on and 不会过滤结果记录条数,只会根据and后的条件是否显示 B表的记录,A表的记录一定会显示。 不管and 后面的是A.id=1还是B
SQL 语句中 left join 后用 on 还是 where,区别大了!
|
SQL 语音技术 数据库
SQL基础【十五、join、Inner join、Left join、Right join、Full join】
SQL基础【十五、join、Inner join、Left join、Right join、Full join】
170 0
SQL基础【十五、join、Inner join、Left join、Right join、Full join】
|
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的记录。
135 0
left join 后用 on 还是 where,区别大了!
SQL优化--inner、left join替换in、not in、except
SQL优化--inner、left join替换in、not in、except新系统上线,用户基数16万,各种查询timeout。打开砂锅问到底,直接看sql语句吧,都是泪呀,一大堆innot inexcept。
1378 0