用于开发 .NET 业务 Web 窗体的创新架构 (2) - 如何实现查询
本系列文章介绍了一种用于企业软件开发中开发业务 Web 窗体的创新架构,与传统的 ASP.NET 或 MVC 开发相比,它具有更好的性能、更高的生产力、更强的可配置性和更易于维护性。
引言
本系列文章介绍了一种用于企业软件开发中开发业务 Web 窗体的创新架构,与传统的 ASP.NET 或 MVC 开发相比,它具有更好的性能、更高的生产力、更强的可配置性和更易于维护性。这是本系列的第二篇文章。在继续之前,您应该在 <<RapidWebDevUI 概述>> 中查看第一篇文章以了解概念和概览。本文将介绍“查询”的工作原理以及如何在 Web 窗体中配置查询面板。
“查询”的工作原理
查询面板的开发由 XML 配置和对接口 IDynamicPage
的 Query
方法的实现组成,如下面的代码片段所示。
<QueryPanel HeaderText="Query Users">
<TextBox FieldName="UserName" Label="UserName: " />
<TextBox FieldName="DisplayName" Label="DisplayName: " />
<CheckBoxGroup FieldName="Membership.IsApproved"
FieldValueType="System.Boolean" Label="Approved: " Occupation="1">
<Item Text="Yes" Value="true" Checked="true" />
<Item Text="No" Value="false" />
</CheckBoxGroup>
</QueryPanel>
/// <summary>
/// Execute query for results binding to dynamic page grid.
/// </summary>
/// <param name="parameter">Query parameter.</param>
/// <returns>Returns query results.</returns>
QueryResults Query(QueryParameter parameter);
RapidWebDev UI 框架根据 QueryPanel
XML 元素中的过滤器进行配置来渲染查询面板的 UI。默认支持的查询过滤器控件类型有 CheckBox
、CheckBoxGroup
、ComboBox
、Date
、DateTime
、Integer
、Decimal
、TextBox
和 RaduiGroup
。当所有这些控件都不能满足您的要求时,您可以使用 Custom
XML 元素来配置您开发的自定义查询过滤器控件,该控件遵循自定义查询过滤器控件的规范。如上文的查询面板配置所示,渲染的 UI 如下面的屏幕截图所示。

当 RapidWebDev UI 框架渲染查询面板的 UI 时,有一个 JavaScript 管理器实例为查询面板注册到 Web 浏览器中,该管理器负责管理所有查询过滤器,包括它们的状态和值。当单击“查询”按钮时,查询面板管理器实例会收集每个查询过滤器的用户输入,并组装一个异步 HTTP 请求发送到动态页面的 RapidWebDev 数据服务以获取 JSON 数据响应,例如~/ObjectId/DynamicPageDataService.svc。我使用 Fiddler2 跟踪 HTTP 请求和响应,如下面的屏幕截图所示。返回 4 条记录的数据响应仅为 **2.5KB**。

最后,查询面板管理器将 JSON 数据渲染到网格中。

查询面板 XML 配置
上面提到的默认支持的查询过滤器控件类型具有通用属性,如 Label
、FieldName
、Operator
、FieldValueType
和 Occupation
。Label
是 UI 中查询过滤器的标签,例如“用户名:”。Label
支持变量标记,如 $VariableName$
或“$Namespace.ClassName.StaticPropertyName, AssemblyName$
”。VariableName
应通过接口 IDynamicPage
的 SetupContextTempVariables
方法进行设置。
FieldName
用于框架通过 IPredicateCompiler
(命名空间:RapidWebDev.UI.DynamicPages
)的实现自动组装查询表达式。它支持关联对象的属性。例如,我们配置一个动态页面来管理用户,页面的主要入口是 User
。实体 User
引用 Membership
。我们希望通过 Membership
的属性(如上面代码片段中的 Membership.IsApproved
)来查询用户。Linq2SQL 谓词编译器(类:RapidWebDev.UI.DynamicPages.Linq2SQLPredicateCompiler
)将查询过滤器编译为表达式,如
var query = from user in dataContext.Users
where user.Membership.IsApproved
select user;
Operator
是查询条件的运算符,支持 Equal
、StartsWith
、Like
、In
、NotIn
、GreaterThan
、GreaterEqualThan
、LessThan
、LessEqualThan
和 Between
。默认情况下,框架根据查询过滤器控件类型选择运算符。
FieldValueType
是查询表达式参数值的 CLR 类型。如果指定了 FieldValueType
,则在组装查询表达式时,查询过滤器控件的值将被隐式转换为目标类型。
Occupation
指示查询过滤器控件在渲染的查询面板中占用多少单元格。例如,查询面板布局实现 TableXColumnsQueryPanelLayout
在 HTML table
中渲染所有查询过滤器。Occupation
表示查询过滤器控件占用的列数。
除了这些通用属性外,最好查看 DynamicPage.xsd
以了解每个查询过滤器控件的扩展属性。
查询实现
RapidWebDev 动态页面的数据服务将异步查询请求转换为 QueryParameter
,其中包含查询和排序信息。QueryParameter
可以通过 IPredicateCompiler
(命名空间:RapidWebDev.UI.DynamicPages
)的实现转换为查询和排序表达式,该实现已在 Spring.NET IoC 中配置。如下面查询产品的实现所示,我们只需要将编译后的查询和排序表达式与 Linq2SQL lambda 表达式进行转换和连接。而无需显式组装查询表达式。因此,我们可以轻松处理查询过滤器的需求变更,而无需重新编译。返回的 QueryResults(int recordCount, IEnumerable results)
会被框架自动序列化为 JSON 数据。
/// <summary>
/// Query products by parameters.
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public override QueryResults Query(QueryParameter parameter)
{
using (ProductManagementDataContext ctx =
DataContextFactory.Create<ProductManagementDataContext>())
{
IQueryable<Product> q = from p in ctx.Products
where p.ApplicationId ==
authenticationContext.ApplicationId
select p;
LinqPredicate predicate = parameter.Expressions.Compile();
if (predicate != null && !string.IsNullOrEmpty(predicate.Expression))
q = q.Where(predicate.Expression, predicate.Parameters);
if (parameter.SortExpression != null)
q = q.OrderBy(parameter.SortExpression.Compile());
int recordCount = q.Count();
var results = q.Skip(parameter.PageIndex * parameter.PageSize)
.Take(parameter.PageSize).ToList();
return new QueryResults(recordCount, );
}
}
动态数据
我们可能需要动态支持 XML 中无法配置的需求,例如,为具有不同权限的用户渲染不同的查询过滤器,或者查询面板中下拉列表框的项应从数据库中获取。 RapidWebDev 支持此类场景。动态页面的 XML 配置可以配置一个回调函数,在 UI 渲染之前更改配置,请参阅 DynamicPage.xsd
中的 Page
/@ProcessCallbackType
。我们可以在回调函数中在运行时更改配置。此外,我们可以为下拉列表框查询过滤器配置 DynamicDataSource
。DynamicDataSource
被配置为从 JSON 驱动的外部 Web 服务拉取项,如下面的代码片段所示。因此,在该示例中,当用户选择或在可编辑的 combobox
中输入文本时,combobox
会从外部服务刷新匹配的项。
<ComboBox FieldName="ParentHierarchyDataId" Label="Parent: " Editable="true"
MinChars="2" FieldValueType="System.Guid" ForceSelection="true">
<DynamicDataSource Url=
"/Services/HierarchyService.svc/json/FindByKeyword?limit=999"
Method="GET" TextField="Name" ValueField="Id" QueryParam="q">
<Param Name="hierarchyType" Value="$HierarchyType$" />
</DynamicDataSource>
</ComboBox>
查询面板布局
IQueryPanelLayout
接口用于渲染查询面板的布局。 RapidWebDev 在 1.51 版本中实现了一个基于 html table
的布局,称为 RapidWebDev.UI.DynamicPages.TableXColumnsQueryPanelLayout
。如果您有其他需求,可以实现一个新的策略并将其配置到 Spring.NET IoC 中,而不是当前 RapidWebDev.Web\Spring\ui.config 中的 TableXColumnsQueryPanelLayout
。
什么是RapidWebDev
网站: http://www.rapidwebdev.org
RapidWebDev 是一个基础设施,可帮助工程师轻松高效地开发 Microsoft .NET 中的企业软件解决方案。它由一个可扩展且可维护的 Web 系统架构组成,包含一套通用的业务模型、API 和服务,作为开发几乎所有业务解决方案所需的基本功能。因此,当工程师使用 RapidWebDev 进行开发时,他们可以获得许多可重用且现成的东西,然后可以更专注于业务逻辑的实现。实际上,与传统的 ASP.NET 开发相比,我们可以节省超过 50% 的时间来开发高质量、高性能的业务解决方案。