这篇博文纪录一下:使用 EF7,当 Linq 查询中使用 "Left Join" 语法(DefaultIfEmpty),Where Select 不同条件语法实现,出现的不同问题。

为了正确反应测试 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 等等,但都和上面比较类似,这边就不纪录了。


已提交至 EntityFramework 7 issues:Use EF7, Linq Left Join Where Select is error.

EntityFramework 7 Left Join Where Select 奇怪问题的更多相关文章

  1. EntityFramework 7 Left Join Where is error(Test record)

    First of all, my English is very poor, so I may not be a very good expression, very sorry! In this b ...

  2. EntityFramework 7 Join Count LongCount 奇怪问题

    先吐槽一下,EF7 目前来说,真对的起现在的版本命名:"EntityFramework": "7.0.0-beta1". 这篇博文纪录一下:当 Linq 查询中 ...

  3. EntityFramework 7 Join Count LongCount 奇怪问题(已修复)

    问题说明: 博客问题纪录 Use EF7, Linq Join Count is error EF7 Code Commit EF7 版本(注意 rc): 旧版本:"EntityFramew ...

  4. 成功的拆开了SELECT里JOIN个SELECT是啥

    SELECT * FROM table JOIN table ON a=b ----------------------- JOIN (SELECT* FROM table JOIN table ON ...

  5. JavaPersistenceWithHibernate第二版笔记-第六章-Mapping inheritance-006Mixing inheritance strategies(@SecondaryTable、@PrimaryKeyJoinColumn、<join fetch="select">)

    一.结构 For example, you can map a class hierarchy to a single table, but, for a particular subclass, s ...

  6. 爱与恨的抉择:ASP.NET 5+EntityFramework 7

    EF7 的纠缠 ASP.NET 5 的无助 忘不了你的好 一开始列出的这个博文大纲,让我想到了很久之前的一篇博文:恋爱虽易,相处不易:当EntityFramework爱上AutoMapper,只不过这 ...

  7. ASP.NET 5+EntityFramework 7

    爱与恨的抉择:ASP.NET 5+EntityFramework 7   EF7 的纠缠 ASP.NET 5 的无助 忘不了你的好 一开始列出的这个博文大纲,让我想到了很久之前的一篇博文:恋爱虽易,相 ...

  8. 对于SQL的Join,在学习起来可能是比较乱的。我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚。Coding Horror上有一篇文章,通过文氏图 Venn diagrams 解释了SQL的Join。我觉得清楚易懂,转过来。

     对于SQL的Join,在学习起来可能是比较乱的.我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚.Codi ...

  9. MySQL SELECT语法(三)JOIN语法详解

    源自MySQL 5.7 官方手册:13.2.9.2 JOIN Syntax SELECT select_expr From table_references JOIN... WHERE... 如上所示 ...

随机推荐

  1. 【WPF】WPF中的List<T>和ObservableCollection<T>

    在WPF中 控件绑定数据源时,数据源建议采用 ObservableCollection<T>集合 ObservableCollection<T> 类:表示一个动态数据集合,在添 ...

  2. 李洪强iOS经典面试题156 - Runtime详解(面试必备)

    李洪强iOS经典面试题156 - Runtime详解(面试必备)   一.runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C ...

  3. [LintCode] Maximum Subarray 最大子数组

    Given an array of integers, find a contiguous subarray which has the largest sum. Notice The subarra ...

  4. 使用Python中PIL图形库进行截屏

    目的:通过使用Python的一个图形库PIL(Python Image Library)对屏幕进行截图 步骤: 1.下载PIL(路径)并安装 2.新建文件“截屏.py”,右键Edit with IDL ...

  5. python 之 Django 小案例

    一, F  Q # F 使用查询条件的值 # # from django.db.models import F # models.Tb1.objects.update(num=F('num')+1) ...

  6. initWithCoder与initWithFrame的区别

    1. initWithFrame方法是什么?   initWithFrame方法用来初始化并返回一个新的视图对象,根据指定的CGRect(尺寸). 当然,其他UI对象,也有initWithFrame方 ...

  7. 回忆那些我们曾今铭记过的.NET重点知识

    正如标题所说的那样,到底是那些.NET的知识点呢?     接下来就让我带着你们去了解这些知识点吧! 1.接口 2.索引器 3.FOREACH的本质 4.匿名内部类 5.运算符的重载 一.什么是接口? ...

  8. jqueryui 进度条使用

    <title></title> <script src="../Js/NewJs_CFJ/jquery.js" type="text/jav ...

  9. mysql之触发器trigger

    触发器(trigger):监视某种情况,并触发某种操作. 触发器创建语法四要素:1.监视地点(table) 2.监视事件(insert/update/delete) 3.触发时间(after/befo ...

  10. 关于bootstrap和响应式布局

    bootstrap导入 首先需要安装好插件 然后就是在代码器写导入代码 代码如下 <html lang="zh-CN"> <head> <meta c ...