导航属性过滤器

时间:2013-01-30 18:46:55

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

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

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

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

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

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

    // 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");

...获取所有未删除的Todos,或者......

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

...获取所有已删除的Todos。

但是,让我们说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方法本身,还是Entity Framework的一部分(请注意,过滤包含扩展名为not supported in EF。)

1 个答案:

答案 0 :(得分:1)

尽管我们已经讨论过允许过滤“扩展”的想法,但是微风现在无法完全满足您的要求,但我们真的需要更多关于社区是否会发现这些内容的反馈。请将此添加到微风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)我们正在返回一个IQueryable of Object而不是Tou的IQueryable

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

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

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

4)EF 支持支持此功能。