在VS 11 LightSwitch应用程序中使用保存和查询管道来标记和筛选数据

[原文发表地址] Using the Save and Query Pipeline to Flag and Filter Data with LightSwitch in Visual Studio 11

[原文发表时间] 2012-04-26 7:12

说明:此信息适用于Visual Studio 11中的LightSwitch(LightSwitch V2)

在商务应用程序中,根据业务规则有时我们需要额外属性来标记记录,然后在整个应用程序中以某种方式筛选出那些标记过的记录。例如,我们可能有一些关键的信息或历史数据,我们必须将其存储在数据库中,并永远不会删除这些数据。我曾经在卫生保健行业工作过,保持患者的历史数据是很重要的。因此我们不允许用户从系统中删除病人的医院访问信息。但是随着时间的推移,这导致我们的数据集变得很大,并且不能让用户专心地寻找他们需要的相关信息。因此,我们需要一种方式来标记这些记录,然后在整个应用程序中筛选出这些数据。

去年我写了一篇文章,它是基于 LightSwitch Visual Studio 2010 (LightSwitch V1) 的,并展示了如何使用存储和查询管道来存档和筛选记录— — 有效地将其删除,但实际上并非把它们从系统中删除掉:使用保存和查询管道来"存档"已删除的记录。通过使用新的实体集筛选器, Visual Studio 11中LightSwitch (LightSwitch V2)的筛选机制大大地改善了。

在这篇文章中,我将向你展示如何使用新的实体集筛选器方法来应用全局记录筛选器。但首先,让我们一起来回顾一下如何使用保存管道来标记这些记录。

攻到保存管道

任何时候更新、插入或删除实体时,保存管道在中间层中运行。这就是你可以编写商务逻辑的地方,它会在中间层处理更改,并保存到数据存储。让我们看一个例子,在这里我们不想从系统中物理删除客户。这里是此示例的数据模型。请注意我在Customer中创建了一个称为“IsDeleted”的必需字段,它是布尔值类型的。我已经在属性窗口中取消选中"在默认情况下显示",那样字段在任何屏幕上都是不可见的。

image_thumb[11]

当用户尝试删除一个客户时,为了以编程方式标记IsDeleted字段,只需选择数据设计器中的Customer实体,然后下拉"编写代码"按钮,并选择Customers_Deleting方法。

image_thumb[16]

这里是我们需要编写的2行代码:

  1: Private Sub Customers_Deleting(entity As Customer)
  2: 'First discard the changes, in this case this reverts the deletion
  3: entity.Details.DiscardChanges()
  4: 'Next, change the IsDeleted flag to "True"
  5: entity.IsDeleted = True
  6: End Sub

请注意,首先,为了让该实体恢复到其未变更的状态,我们必须调用 DiscardChanges。然后我们只需简单地将IsDeleted字段设置为 True,这会让该实体回到更改的状态。所以现在相应的存储管道方法 (Customers_Updating& Customers_Updated)将自动运行。你可以通过使用entity.Details.EntityState 属性来检查该实体的状态。

此存储管道代码在 LightSwitch V1 中保持不变。然而在 LightSwitch V2中,我们需要以不同的方式筛选数据。让我们看看如何实现。

使用实体集筛选器

既然我们已成功地标记了已删除的客户,接下来做的是将它们从查询中滤除掉,那样它们不会显示在用户所操作的屏幕上。在LightSwitch V2 中添加了一种新的查询拦截方法,EntitySet_ 筛选器,它可以让你指定一个筛选器,无论在任何时候当引用一个实体集时,都可应用此筛选器。(查看LightSwitch 团队博客中最近由MichaelSimon所写的文章:使用实体集筛选器来筛选数据来了解这项新功能的详细信息)

与其在LightSwitch V1中我们不得不使用Customers_All_PreprocessQuery 如这儿所示),不如将IsDeleted筛选器应用在Customers_Filter方法中。实体集筛选器优胜于All_PreprocessQuery 方法,因为任何时候在引用实体集时,就会执行筛选器方法,即使该实体并不是查询的直接目标。这启用了跨应用程序的真正的行级别筛选。

所以对于此示例,选择数据设计器中的Customer实体,然后下拉"编写代码"按钮,并选择Customers_Filter方法。

image_thumb[27]

在这里我们需要编写 lambda 表达式来作为筛选器的谓语。

  1: Private Sub Customers_Filter(ByRef filter As Expressions.Expression(Of Func(Of Customer, Boolean)))
  2: filter = Function(c) c.IsDeleted = False
  3: End Sub

这些表达式起初看起来有些棘手,但它们只是需要一些实践。你可以思考是否这些作为内嵌函数。这个采用客户参数,然后返回布尔表达式来用于筛选记录。你可以筛选出任何你想要的,甚至像Michael在他的博客中所展示的来基于安全权限筛选。(至于Lambda 表达式的详细信息,请参阅:Lambda 表达式 (Visual Basic)Lambda 表达式 (C#).)

既然我们已经设置好了保存和查询管道来处理"已删除"的客户,我们可以运行该应用程序。当用户删除一位客户时,这与从数据库中物理删除客户的行为是完全相同的。

image_thumb[24]

如果我们进入数据库中实际的Customer表,你可以看到它们被正确地标记了。

image_thumb[26]

此外,现在当我们编写一个Customers不是直接目标的查询时,行筛选将仍然适用。比如,我们有一个称为做Regions的父表。如果我们想要创建一个查询"超过10位客户的地区",我们会如下所示编写我们的查询:

  1: Private Sub RegionsOver10Customers_PreprocessQuery(ByRef query As IQueryable(Of Region))
  2: query = From r In query
  3: Where r.Customers.Count > 10
  4: End Sub

在LightSwitch V1 中,当我们执行此查询时,不会调用Customers_All_PreProcessQuery中的其他筛选器。它会将已标记为IsDeleted客户计算进去 — — 这不是我们想要的。你不得不将该筛选项包含到此查询结果中。所以如果在你的应用程序中,你有很多间接引用Customers的查询,那么这将很难维护。在 LightSwitch V2 中,无论何时引用Customer实体集,不管它是否是查询的直接目标,都始终会调用 Customers_Filter 方法,所以此查询总将返回预期的结果。

因为我们想要鼓励使用这种方法来实现真正的行级筛选,新的 LightSwitch V2 项目不再有针对EntitySet_All_PreProcessQuery 方法的入口点。从 V1中升级的项目仍会像以前一样运行,你将看到他们在Solution Explorer中作为模型化查询。因此,不会对你的应用程序造成任何重大的更改,但你会想要强烈考虑使用该实体集筛选器方法。

总结

我希望这篇文章展示了当处理保存和查询管道中的数据时,LightSwitch是多么的强大、简单。我们已经加强了全局过滤技术,那样,它可以处理像我上述的方案,以及Michael 展示的行级别安全方案。如果你正在使用 _All_PreProcessQuery 方法,然后当你升级到 Visual Studio 11 时,它们将继续运行。但是,无论如何访问实体,全局筛选器都会运行,所以你可以使用实体集筛选器方法来代替它。

希望大家喜欢!