【问题标题】:Navigation Property Filter导航属性过滤器
【发布时间】:2013-01-14 17:00:08
【问题描述】:

我的问题是:如何为navigation property 实现默认的服务器端“过滤器”?

在我们的应用程序中,我们很少真正从数据库中删除任何内容。相反,我们实现了“软删除”,其中每个表都有一个Deleted 位列。如果此列为真,则记录已被“删除”。如果它是假的,它就没有。

这使我们可以轻松“取消删除”客户意外删除的记录。

默认情况下,我们当前的 ASP.NET Web API 仅返回“未删除”的记录,除非客户端将 deleted 参数作为 true 发送。这个想法是服务的消费者不必担心指定他们只想要未删除的项目。

在 Breeze 中实现同样的功能非常简单,至少对于基础实体而言是这样。例如,这里将是经典 Todo 示例的实现,添加一个“已删除”位字段:

    // Note: Will show only undeleted items by default unless you explicitly pass deleted = true.
    [HttpGet]
    public IQueryable<BreezeSampleTodoItem> Todos(bool deleted = false) {
        return _contextProvider.Context.Todos.Where(td => td.Deleted == deleted);
    }

在客户端,我们需要做的就是……

var query = breeze.EntityQuery.from("Todos");

...获取所有未删除的待办事项,或者...

var query = breeze.EntityQuery.from("Todos").withParameters({deleted: true})

...获取所有已删除的待办事项。

但是假设一个 BreezeSampleTodoItem 有一个子集合,用于完成该 Todo 所需的工具。我们将其称为“工具”。工具还实现了软删除。当我们执行一个使用 expand 的查询来获取带有其工具的 Todo 时,它将返回所有工具 - “删除”与否。

但是Todo.Tools展开时如何默认过滤掉这些记录呢?

我想到每个可能需要扩展的项目都有单独的 Web API 方法,例如:

[HttpGet]
public IQueryable<Todo> TodoAndTools(bool deletedTodos = false, bool deletedTools = false)
{
    return // ...Code to get filtered Todos with filtered Tools
}

我在another SO post 中找到了一些如何执行此操作的示例代码,但它需要手动编码 Todo 的每个属性。上述帖子中的代码也返回List,而不是IQueryable。此外,这需要为每个可能的扩展添加方法,这并不酷。

基本上,我正在寻找的是某种方式来定义一段代码,该代码在查询Todos 时被调用,而另一个用于每当查询Tools 时 - 最好能够传递一个定义它是否存在的参数应该返回已删除的项目。这可能是服务器端堆栈上的任何位置 - 无论是在 Web API 方法中、本身还是实体框架的一部分(请注意,过滤包含扩展是 not supported in EF。)

【问题讨论】:

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


    【解决方案1】:

    Breeze 目前无法完全满足您的要求,尽管我们已经讨论了允许过滤“扩展”的想法,但我们确实需要更多反馈来了解社区是否会觉得这很有用。请将此添加到微风User Voice 并投票。我们非常重视这些建议。

    此外,正如您所指出的,EF 不支持这一点。

    但是...您可以做的是使用投影而不是展开来做非常相似的事情:

    public IQueryable<Object> TodoAndTools(bool deleted = false
                                          ,bool deletedTools = false) {
        var baseQuery = _contextProvider.Context.Todos.Where(td => td.Deleted == deleted);
        return baseQuery.Select(t => new {
          Todo: t,
          Tools: t.Tools.Where( tool => tool.Deleted = deletedTools);
        });
     }
    

    这里有几点需要注意:

    1) 我们返回的是 Object 的 IQueryable 而不是 ToDo 的 IQueryable

    2) Breeze 将检查返回的有效负载并为返回的任何“entityTypes”自动创建微风实体(即使在投影中)。所以这个查询的结果将是一个 javascript 对象数组,每个对象都有两个属性; 'ToDo' 和'Tools' 其中Tools 是'Tool' 实体的数组。好消息是在投影中返回的 ToDo 和 Tool 实体都是“完整的”微风实体。

    3) 您仍然可以根据预计的属性名称传递客户端过滤器。即

    var query = EntityQuery.from("TodoAndTools")
            .where("Todo.Description", "startsWith", "A")
            .using(em);
    

    4) EF 确实支持这一点。

    【讨论】:

    • 谢谢,杰。我去做。我现在意识到另一个障碍:有没有办法禁用给定实体类型的扩展功能?在其他情况下,我们可能不希望通过 API 直接访问实体集合。如果您愿意,我可以将其作为单独的 SO 问题发布。
    • 这是一个很好的问题,所以请添加它。但是...虽然我们的 UserVoice (breezejs.uservoice.com/forums/173093-breeze-feature-suggestions/…) 上有此功能,但目前不存在此功能
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多