使用缓存绑定到数据库键/代码表






4.14/5 (5投票s)
用于管理和缓存典型的事务性网站的键/代码表的库。它提供了一种简单的方法,不仅可以在 DropDownList 等列表中绑定用户友好的描述,还可以将描述读取到详细表中的只读键中,而无需使用大量的 JOIN。
引言
问题所在
大型在线交易处理 (OLTP) 应用程序主要使用近乎第三范式的数据库,其中可能包含许多相对较小的代码表,这些代码表为存储在大表中的 ID 键提供 ID,并为应用程序的表示提供用户友好的描述。.NET 允许将 ID 绑定到 DropDownList
或 RadioButtonList
,但如何显示数据正在查看为只读时的描述?上面的 GridView 有 3 列(共 4 列)的值来自代码表。如果您是用户,您更愿意看到哪个?
Michael Jones |
DC |
1 |
1 |
或
Michael Jones |
District of Columbia |
已婚 |
Male |
检索行以供查看时,您将检索许多列的 ID,而不是要显示给用户的描述。您可以将所有这些列连接到各自的代码表以获取描述,但这会使语句和存储过程更加复杂。例如:
select name, state, mstatid, genderid from userdata where uid = @uid
或
select u.name s.statedesc, m.mstatdesc, g.genderdesc from userdata u join states
s on u.state = s.state join mstat m on u.mstatid = m.mstatid join
gender g on u.genderid = g.genderid where uid = @uid
处理代码表时出现的其他问题是,有时一个代码不再需要,但删除该代码会导致使用它的旧条目出现问题。您创建的所有处理 JOIN 的语句可能不再按您最初的意图工作。例如,假设您购买了手机套餐“A”。后来,手机公司不再提供套餐“A”,而是提供了套餐“B”。套餐“A”对于购买它的人仍然有效,但任何新客户都无法选择套餐“A”。
解决方案的要求
- 代码表不与业务数据连接。
- 为了提高性能,代码表需要被缓存。
- 方便地绑定到代码表,无论是编辑还是只读使用。
- 允许在单个位置管理所有代码表语句。
- 允许禁用任何代码表行,以便
- 在
DropDownList
和RadioButtonList
中,如果需要,禁用的代码将不会出现在列表中。 - 在只读模式下,如果现有记录具有禁用的代码,它将获得正确的描述。
- 在编辑模式下,如果现有记录具有禁用的代码,则列表中只会显示启用的描述和当前绑定的禁用的描述。
- 每个代码表都通过一个简单的描述性名称进行访问。
概述
此示例包含两个主要类和一个接口,可用于任何 ASP.NET 2.0 应用程序。
- CodeTableCache.cs - 当需要时,它检索语句以创建每个代码表的
DataSet
,然后将其存储在缓存中。当只需要启用的代码表时,会在缓存的 DataSet 上使用DataView
。如果某个项目在缓存中,它将返回该值。如果不在缓存中,它将从表中生成DataSet
并将其放入缓存。 - CodeTableDataSource.cs - 这是一个扩展
ObjectDataSource
的控件,可以轻松绑定到正确的代码表数据集,供DropDownList
和RadioButtomList
使用。 - ICodeTableList.cs - 这是一个自定义类必须实现的接口,以便
CodeTableCache
可以检索简单的代码表名称及其对应的语句。
下载中还包含了一些文件,用于演示此功能
- CodeTableList.cs - 实现
ICodeTableList
接口的类。 - EditCodeTables.aspx - 用于修改代码表的网页。这有助于测试禁用的代码功能。
- UseCodeTable.aspx - 这是一个工作示例,其中一个表包含一个文本字段和许多代码表 ID 字段。
- Default.aspx - 方便访问其他两个页面。
- web.config 和 global.asax。
- BuildDatabase.sql 和 Inserts.sql - SQL Server Express 脚本,用于创建此应用程序的数据库。
要使用此示例,请在 IIS 中或在 Visual Studio 的目录中进行安装。在 SQL Server 或 Express 中创建一个数据库,并执行 BuildDatabase.sql 和 Inserts.sql 脚本来构建表。可能需要修改 web.config 中的连接字符串以访问数据库。
如果您没有 SQL Server 或 Express,可以从 Microsoft 免费下载它和 Management Studio:Microsoft SQL Server Express 和 Microsoft SQL Server Management Studio Express。我不是 SQL Server Express 用户,并且在我的一台系统上无法成功连接到服务器。如果您遇到同样的问题,请在 web.config 中为应用程序设置模拟。需要添加的节点是
<identity impersonate="true" password="win_pwd" username="machinename\winlogin" />
使用代码
在 ASPX 页面中,可以像这样简单地添加一个数据源。这些数据源用于 DropDownList
和 RadioButtonList
的列表项。在示例中,AgreementDS
被两个 RadioButtonList
使用。因此,如果您获取多个地址,则只需要定义一个状态数据源。CodeType
字段必须与 CodeTableList
类中代码表的简单名称匹配。默认情况下,“Disabled”代码不会出现在这些列表中。将 DisplayEnabledOnly
设置为 False
以查看所有值。
<opp:CodeTableDataSource ID="StatesDS" runat="server" CodeType="States" />
<opp:CodeTableDataSource ID="GenderDS" runat="server" CodeType="Gender" />
<opp:CodeTableDataSource ID="MaritalStatusDS" runat="server" CodeType="MaritalStatus" />
<opp:CodeTableDataSource ID="SatisfactionVDS" runat="server"
CodeType="Satisfaction" IdValue="SatisValue" />
<opp:CodeTableDataSource ID="SatisfactionQDS" runat="server"
CodeType="Satisfaction" IdValue="SatisQuality" />
<opp:CodeTableDataSource ID="AgreementDS" runat="server" CodeType="Agreement" />
请注意,“Satisfaction”CodeType
有两个条目,它们的 IdValue
不同。这些被配置为即使被禁用,也将现有行的代码 ID 添加到列表中。还记得上面的手机套餐示例吗?还需要另外两项才能使其正常工作。首先,在 GridView
、DetailsView
或 FormView
中,将所需的列添加到 DataKey
属性。其次,在代码隐藏的 Page_Load
中,告知 CodeTableDataSource
如何查找当前选定的值。
SatisfactionVDS.DatakeyValues = TestTableDetail.DataKey.Values;
SatisfactionQDS.DatakeyValues = TestTableDetail.DataKey.Values;
这不仅限于新的 ASP.NET 2.0 GridView
、DetailsView
和 FormView
,尽管它是为它们设计的。需要做的是将 DatakeyValues
属性设置为一个 IOrderedDictionay
,其键与 IdValue
属性匹配。
对于 DropDownList
或 RadioButtonList
,将 DataValueField
设置为“ID”,将 DataTextField
设置为“Description”,将 DataSourceID
设置为相应的 CodeTableDataSource
,将 SelectedValue
设置为绑定的字段。要为只读值获取描述,只需将 Eval()
值传递给 GetCodeDesc
方法,并直接在 ASPX 页面中使用正确的 CodeType
。
<asp:TemplateField SortExpression="AgreeUseAgain" HeaderText="Would you use again?" >
<EditItemTemplate>
<asp:RadioButtonList ID="RadioList2" DataValueField="ID"
DataTextField="Description" DataSourceID="AgreementDS"
Runat="server" SelectedValue='<%# Bind("AgreeUseAgain") %>' />
</EditItemTemplate>
<ItemTemplate>
<asp:Label Runat="server" id="Label6"
Text='<%# CodeTableCache.GetCodeDesc("Agreement",
Eval("AgreeUseAgain").ToString()) %>' />
</ItemTemplate>
</asp:TemplateField>
如何将库集成到您的应用程序中
- 在应用程序中使用时,将 App_Code/OppSol 目录中的文件添加到新应用程序的同一目录中。
- 创建一个实现
ICodeTableList
类的类。只需要四种方法。 - 创建了
CodeTableList
类后,只需将其注册到CodeTableCache
即可。 - 准备使用新功能所做的最后一次更改是添加
CodeTableDataSource
控件并使其在您的网页中可访问。我将其添加到了 web.config 中,但也可以在 ASPX 文件中为每个页面进行设置。<pages> <controls> <add namespace="OppSol.Software.CodeTableHelpers" tagPrefix="opp"/> </controls> </pages>
string GetStatement(string CacheCode);
string GetConnectionString(string CacheCode);
System.DateTime GetExpiration(string CacheCode);
bool IsAvailable(string CacheCode);
CacheCode
是给每个代码表起的简单名称。例如:States 代码表可以仅用“States”来识别。GetStatement
方法最重要,它应该获取表的所有行。语句中所需的列是“ID”、“Description”和“Disabled”。如果您的代码表使用不同的列名,它们必须别名为这些名称。如果您没有“Disabled”列,只需返回文字值 'false',这将使所有行都处于启用状态。如果您稍后添加了禁用列,只需在此处更改语句即可使其正常工作。States 表语句如下所示 - select state AS ID, name AS Description, 'false' AS Disabled from states order by name.
在示例应用程序中,我创建了一个可以管理多个代码表的单个代码表。它有一个 codetype 列,该列必须与应用程序中使用的 CacheCode
匹配。
GetConnectionString
方法将返回连接字符串。如果您的代码表位于不同的数据库或架构中,可以使用不同的连接字符串。GetExpiration
返回缓存项应从缓存中删除的时间。代码表的值是缓慢变化的,因此它们非常适合缓存。由于它们会发生变化,因此设置合理的过期时间是一个好习惯。在高流量网站上,即使是像 1 分钟这样短的过期时间也能节省许多数据库往返。IsAvailable
将只返回 CacheCode
是否为有效的 CacheCode
。
示例中的 CodeTableList
类继承自 StringDictionary
,用于跟踪 CacheCode
和语句。您的类可以使用任何方法来跟踪这些信息,包括 XML 文件或单独的数据库表。
CodeTableCache
是一个静态类,因此您的整个应用程序只有一个实例。静态类永远不需要用 new
来实例化。当您需要调用方法时,只需调用它即可。在应用程序启动时注册类与 CodeTableCache
是最佳时机。global.asax 提供了这样一个事件。将以下代码添加到您的 global.asax 中
void Application_Start(object sender, EventArgs e)
{
if (OppSol.Software.CodeTableHelpers.CodeTableCache.StatementList == null)
OppSol.Software.CodeTableHelpers.CodeTableCache.StatementList =
new CodeTableList();
}
就是这样。希望您觉得它像我一样有用。
关注点
我在几个大型应用程序中使用了此功能的稍早版本,效果非常好。此示例使用 SQLDataSource
来处理主表,我不推荐这样做。我喜欢使用自定义业务对象,这可能是我下次集成代码表的地方。
另一个未来的增强功能可能是自定义业务对象来保存代码表数据,这将允许一些额外的功能。但目前,DataSet
/DataView
组合太简单了,所以我们得拭目以待。
我最不喜欢这个解决方案的一点是需要设置 DatakeyValues
属性。我不知道有没有更优雅的方式可以从控件中获取当前绑定行中的值。您有什么想法吗?
如果您对代码表有任何想法或增强建议,请在下方的讨论中发表评论。
历史
- 2006/10/03 - 首次修订版发布于 CodeProject。