我正在维护一个带有Entity framework 6和MSSQL服务器数据库的ASP.NET WebAPI2应用程序。IoC集装箱是温莎城堡。我在我的存储库中有一个方法,用于从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]
我想我做错了什么,但我不知道是什么。任何想法都将不胜感激。
EDIT:我刚刚注意到一些奇怪的事情——在生成的SQL中没有WHERE子句,这意味着所有的行都是从数据库中选择的,带到客户端,并在那里进行过滤。EDIT 2:使用LINQ查询语法生成相同的SQL。编辑3:在编写了一个单元测试之后,我手动实例化了存储库和服务(而不是将其留给CastleWindsor),运行测试时生成的SQL具有where子句。
如果您的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>
,所以这是可以的。但由于看起来你有一个自定义的存储库实现,我怀疑幕后还会发生什么。。。