【问题标题】:BreezeJS does not perform filtering in database?BreezeJS 不在数据库中执行过滤?
【发布时间】:2013-10-05 05:49:50
【问题描述】:

我在客户端使用以下查询:

var query = breeze.EntityQuery.from("AllCustomers").where("CustomerId,"==",criteriaValue);
return this.manager.executeQuery(query)

这会产生以下网址: /breeze/myAPI/AllCustomers?$filter=CustomerId%20eq%2012

我注意到在数据库中没有执行过滤(数据库执行的SQL中没有WHERE语句)。我怀疑,原因是Breeze.WebApi.QueryHelper.WrapResult,它调用Enumerable.ToList。后者将 IQueriable 转换为列表,在默认情况下 Microsoft OData 实现过滤 if 之前强制执行查询:

// if a select or expand was encountered we need to
// execute the DbQueries here, so that any exceptions thrown can be properly returned.
// if we wait to have the query executed within the serializer, some exceptions will not
// serialize properly.
queryResult = Enumerable.ToList((dynamic)queryResult);
queryResult = PostExecuteQuery((IEnumerable)queryResult);

这是 Breeze 中的错误还是我做错了什么?

我正在为实体框架使用 Oracle ODP.NET 提供程序。

更新:我正在使用 WebAPI 和控制器方法非常简单:

[BreezeController]
public class MyController : ApiController
{

[HttpGet]
public IQueryable<Customer> AllCustomers()
{            
  return  _contextProvider.Context.Customers;
}

【问题讨论】:

    标签: entity-framework asp.net-web-api odata breeze


    【解决方案1】:

    好的,这是一个错误并已修复。该修复程序将在我们的下一个完整测试版本(v 1.4.3)中提供,或者您现在可以从 Breeze Git 存储库获取我们当前的开发版本。

    请注意,此问题仅发生在针对涉及服务器上的“命名查询”且客户端没有查询资源的实体类型/资源名称映射的查询的构造错误的过滤器时。在 Breeze 客户端确实具有 entityType/resourceName 映射的情况下,任何无效的过滤器都会在进入服务器之前引发客户端错误。

    并且...感谢您的报告。 :)

    【讨论】:

    • 谢谢。修复的提交是什么? github.com/IdeaBlade/Breeze/commit/… ?
    • 只取最新的,我们尽量确保它总是干净地构建。请注意,在我们发布之前,它仍会被标记为 1.4.2。
    • 我明白这一点。我只是好奇,修复是什么,因为我无法自己修复它:-)
    • 啊,好的。看看 c94b20d5141c72b8295b179b93638a70670133f6。解决方法是向 BreezeQueryableAttribute 添加一个 if (!actionExecutedContext.Response.IsSuccessStatusCode) 调用。
    【解决方案2】:

    一般而言,过滤条件将应用于 SQL 查询中的数据层。

    您引用的代码片段...似乎强制过早执行查询以检索整个表的代码片段...似乎仅在您的客户端查询执行选择或展开时才起作用.我没有在您的查询中看到选择或展开。是什么让您认为 Breeze.WebAPI 在您的案例中遵循这个特定的代码路径?您是否忘记告诉我们您对“AllCustomers”Web API 方法的实施情况?

    【讨论】:

    • 因为我已经用调试器追踪到了这个位置。它是从 BreezeQueryableAttribute.OnActionExecuted 调用的。
    • 我想我不够清楚。正如代码明确指出的那样,它认为您正在执行在客户端请求中不明显的选择或展开。此外,Breeze 会在执行该查询之前将过滤条件添加到查询中。您正在描述我们在格式正确的服务器方法中从未见过的行为。我们确实需要查看控制器类定义(Web API,对吗?您可以省略除“AllCustomers”之外的方法)、“AllCustomers”方法及其属性,以及该方法与返回数据上下文的路径之间的任何代码.
    • 在尝试在简化场景中重现问题时,我发现如果过滤器包含无效的字段名称,则会执行未过滤的 SQL。在这种情况下,选择整个表,转换 ToList(),然后返回 HTTP 400 错误请求。即使过滤器包含有效的字段名称,也会执行有问题的 WrapResult 方法代码片段,但在这种情况下,传入 WrapResult 方法的 queryResult 参数的 ObjectQuery 正确包含 WHERE 表达式。因此,Breeze 不应针对无效请求调用 ToList。
    • 一个有趣的发现!如果我理解正确,客户端提出了一个带有引用无效字段名称的过滤器的查询......并且 Web API 方法完全忽略了过滤器,导致整个表被返回?这不好。通常 BreezeJS 会阻止带有无效字段引用的查询。无论如何,如果 Web API 查询的任何部分无效,则根本不应该执行它。这是一个安全问题!我们将为此部分委派 Web API。我想知道他们为什么让这个通过?无论如何感谢您提供的线索。
    • 您正确理解了第一部分(客户端发送了无效的过滤器),但没有理解第二部分。 BreezeController 发生的情况如下:1) 执行未过滤的 SQL - 将整个表读入内存,2) 向客户端返回 HTTP 400(不返回表的内容)。默认 ApiController 发生的情况只是 2)。所以这不是 WebApi 部分的问题,而是 Breeze 的问题。 ApiController 不执行查询,但 BreezeController 执行。如果由于 HTTP 400 错误请求而无法返回结果,则不应尝试 WrapResults。
    【解决方案3】:

    马特拉,

    我们无法重现此问题。

    如果我执行一个有效的查询:

        var query = new breeze.EntityQuery()
            .from("Employees")
            .where("employeeID","==", 1);
    

    正如我在 Profiler 中看到的那样,创建了正确的 SQL:

    exec sp_executesql N'SELECT 
    [Extent1].[EmployeeID] AS [EmployeeID], 
    [Extent1].[LastName] AS [LastName], 
    [Extent1].[FirstName] AS [FirstName], 
    [Extent1].[Title] AS [Title], 
    [Extent1].[TitleOfCourtesy] AS [TitleOfCourtesy], 
    [Extent1].[BirthDate] AS [BirthDate], 
    [Extent1].[HireDate] AS [HireDate], 
    [Extent1].[Address] AS [Address], 
    [Extent1].[City] AS [City], 
    [Extent1].[Region] AS [Region], 
    [Extent1].[PostalCode] AS [PostalCode], 
    [Extent1].[Country] AS [Country], 
    [Extent1].[HomePhone] AS [HomePhone], 
    [Extent1].[Extension] AS [Extension], 
    [Extent1].[Photo] AS [Photo], 
    [Extent1].[Notes] AS [Notes], 
    [Extent1].[PhotoPath] AS [PhotoPath], 
    [Extent1].[ReportsToEmployeeID] AS [ReportsToEmployeeID], 
    [Extent1].[RowVersion] AS [RowVersion], 
    [Extent1].[FullName] AS [FullName]
    FROM [dbo].[Employee] AS [Extent1]
    WHERE [Extent1].[EmployeeID] = @p__linq__0',N'@p__linq__0 int',@p__linq__0=1
    

    但是,如果我使用无效字段执行查询:

        var query = new breeze.EntityQuery()
            .from("Employees")
            .where("invalidEmployeeID","==", 1);
    

    正如预期的那样,查询甚至没有进入数据库。 您能否提供一个重现该问题的小样本,以便我们进一步调查?

    【讨论】:

    • 我正在使用一个相当非标准的设置:Oracle 实体框架提供程序与跟踪提供程序链接在一起,因此可能很难提供小样本。我可以看到跟踪提供程序记录了查询执行的开始和结束(没有 WHERE 部分)。命中数据库时,调用堆栈如下所示:Breeze.WebApi.QueryHelper.WrapResult(..) Line 231, Breeze.WebApi.dll!Breeze.WebApi.BreezeQueryableAttribute.OnActionExecuted(..) Line 88。违规行是queryResult = Enumerable.ToList((dynamic)queryResult)。您在测试期间是否达到了这条线?
    猜你喜欢
    • 2022-12-06
    • 1970-01-01
    • 1970-01-01
    • 2018-06-10
    • 1970-01-01
    • 2010-10-23
    • 2013-08-19
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多