Entity Framework 6 投影生成 SQL 等价于“Select *”并且不生成 WHERE 子句
Posted
技术标签:
【中文标题】Entity Framework 6 投影生成 SQL 等价于“Select *”并且不生成 WHERE 子句【英文标题】:Entity framework 6 projection generates SQL equivalent to "Select *" and does not produce WHERE clause 【发布时间】:2016-03-12 04:14:55 【问题描述】:我正在使用实体框架 6 和 MSSQL 服务器数据库维护一个 ASP.NET WebAPI2 应用程序。 IoC 容器是 Castle Windsor。我在我的存储库中有一个方法,用于从 DB 获取用户的一些详细信息。由于我不需要每一列,我想我会使用投影。问题是生成的 SQL 选择了我表中的所有列。 这是 DbContext
public partial class SecurityContext : DbContext
public SecurityContext()
: base("name=SecurityContext")
public virtual DbSet<User> secUsers get; set;
这里是在存储库中声明/初始化上下文的地方
public class BaseRepository<T> : IRepository<T> where T : class
protected DbContext context;
public BaseRepository()
context = new SecurityContext();
public BaseRepository(DbContext context)
this.context = context;
//elided
这是存储库中的方法
public User FindUserForLoginVerification(string name)
var loginInfo = context.Set<User>()
.Where(c => c.LoginName == name)
.Select(c => new
LoginName = c.LoginName,
Password = c.HashedPassword,
Salt = c.PasswordHashSalt
)
.SingleOrDefault();
return new User()
LoginName = loginInfo.LoginName,
HashedPassword = loginInfo.Password,
PasswordHashSalt = loginInfo.Salt
;
这是输出 SQL。
SELECT
[Extent1].[UserId] AS [UserId],
[Extent1].[CreatedByUserId] AS [CreatedByUserId],
[Extent1].[Comment] AS [Comment],
[Extent1].[CreatedDate] AS [CreatedDate],
[Extent1].[DefaultCulture] AS [DefaultCulture],
[Extent1].[EmailAddress] AS [EmailAddress],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[IsDeleted] AS [IsDeleted],
[Extent1].[IsExcludedFromPasswordPolicy] AS [IsExcludedFromPasswordPolicy],
[Extent1].[IsChangePassword] AS [IsChangePassword],
[Extent1].[IsLocked] AS [IsLocked],
[Extent1].[LastName] AS [LastName],
[Extent1].[LastPasswordChangeDate] AS [LastPasswordChangeDate],
[Extent1].[LoginName] AS [LoginName],
[Extent1].[NumberOfFailedLoginAttempts] AS [NumberOfFailedLoginAttempts],
[Extent1].[PasswordHash] AS [PasswordHash],
[Extent1].[PasswordHashSalt] AS [PasswordHashSalt]
[Extent1].[UpdatedDate] AS [UpdatedDate]
FROM [dbo].[User] AS [Extent1]
我想我做错了什么,但我不知道是什么。任何想法将不胜感激。
编辑:我刚刚注意到一些奇怪的事情——在生成的 SQL 中没有 WHERE 子句,这意味着所有行都是从数据库中选择的,带到客户端,然后在那里过滤。 编辑 2:使用 LINQ 查询语法生成相同的 SQL。 编辑 3:在编写单元测试后,我手动实例化存储库和服务(而不是将其留给 CastleWindsor),运行测试时生成的 SQL 具有 WHERE 子句。
【问题讨论】:
在您的上下文中,集合是如何声明的?他们有public virtual
还是只有public
为什么是context.Set<User>()
而不是context.secUsers()
?
@GregoryHouseMD 因为在存储库中,上下文作为 DbContext 传递。在回答您的评论之前,我已尝试将其转换为 SecurityContext,但没有产生任何差异。
你试过var loginInfo = context.Set<User>() .Where(c => c.LoginName == name).ToList().Select
...吗?
我注意到通用存储库的行为相同。例如,如果您有类似 context.Set<T>().Where(condition).Select(user => user.Name)
的代码,则不会生成 where 子句或投影。
【参考方案1】:
如果您的context
是从Set<T>
方法返回IEnumerable<T>
(而不是IQueryable<T>
)的东西,那么这就是您的问题,因为表达式:
context.Set<User>
.Where(...)
.Select(...)
.SingleOrDefault()
...将整个表读入内存,然后应用Where
子句和投影(Select
)。所以,你会期待SELECT * FROM table
的行为。
Set<T>
的 DbContext
类实现返回一个 DbSet<T>
,它确实实现了 IQueryable<T>
,这样就可以了。但由于看起来您有一个自定义存储库实现,我怀疑幕后可能发生的其他事情......
【讨论】:
以上是关于Entity Framework 6 投影生成 SQL 等价于“Select *”并且不生成 WHERE 子句的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Entity Framework 6 会为简单的查找生成复杂的 SQL 查询?
Entity Framework 6 Code first:如何使用“循环”关系和存储生成的列来播种数据?
Entity Framework 6 和 mysql TableDetails 强类型异常
如何转换 Entity Framework 6 来为我的模型生成 FluentAPI 定义,而不是数据注释? (我在 VS2015 中使用 MySQL)