我的问题是:如何为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。)
答案 0 :(得分:1)
此外,正如您所指出的,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 支持支持此功能。