【问题标题】:Entity framework 6 projection generates SQL equivalent to "Select *" and does not produce WHERE clauseEntity Framework 6 投影生成 SQL 等价于“Select *”并且不生成 WHERE 子句
【发布时间】: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&lt;User&gt;() 而不是context.secUsers()
  • @GregoryHouseMD 因为在存储库中,上下文作为 DbContext 传递。在回答您的评论之前,我已尝试将其转换为 SecurityContext,但没有产生任何差异。
  • 你试过var loginInfo = context.Set&lt;User&gt;() .Where(c =&gt; c.LoginName == name).ToList().Select...吗?
  • 我注意到通用存储库的行为相同。例如,如果您有类似 context.Set&lt;T&gt;().Where(condition).Select(user =&gt; user.Name) 的代码,则不会生成 where 子句或投影。

标签: c# sql-server asp.net-web-api entity-framework-6


【解决方案1】:

如果您的context 是从Set&lt;T&gt; 方法返回IEnumerable&lt;T&gt;(而不是IQueryable&lt;T&gt;)的东西,那么这就是您的问题,因为表达式:

context.Set<User>
.Where(...)
.Select(...)
.SingleOrDefault()

...将整个表读入内存,然后应用Where 子句和投影(Select)。所以,你期待SELECT * FROM table的行为。

Set&lt;T&gt;DbContext 类实现返回一个 DbSet&lt;T&gt;,它确实实现了 IQueryable&lt;T&gt;,这样就可以了。但由于看起来您有一个自定义存储库实现,我怀疑幕后可能发生的其他事情......

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多