65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.14/5 (5投票s)

2006年10月3日

CPOL

8分钟阅读

viewsIcon

52815

downloadIcon

453

用于管理和缓存典型的事务性网站的键/代码表的库。它提供了一种简单的方法,不仅可以在 DropDownList 等列表中绑定用户友好的描述,还可以将描述读取到详细表中的只读键中,而无需使用大量的 JOIN。

Sample Image - CompCodeTable.jpg

引言

问题所在

大型在线交易处理 (OLTP) 应用程序主要使用近乎第三范式的数据库,其中可能包含许多相对较小的代码表,这些代码表为存储在大表中的 ID 键提供 ID,并为应用程序的表示提供用户友好的描述。.NET 允许将 ID 绑定到 DropDownListRadioButtonList,但如何显示数据正在查看为只读时的描述?上面的 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”。

解决方案的要求

  • 代码表不与业务数据连接。
  • 为了提高性能,代码表需要被缓存。
  • 方便地绑定到代码表,无论是编辑还是只读使用。
  • 允许在单个位置管理所有代码表语句。
  • 允许禁用任何代码表行,以便
    • DropDownListRadioButtonList 中,如果需要,禁用的代码将不会出现在列表中。
    • 在只读模式下,如果现有记录具有禁用的代码,它将获得正确的描述。
    • 在编辑模式下,如果现有记录具有禁用的代码,则列表中只会显示启用的描述和当前绑定的禁用的描述。
  • 每个代码表都通过一个简单的描述性名称进行访问。

概述

此示例包含两个主要类和一个接口,可用于任何 ASP.NET 2.0 应用程序。

  1. CodeTableCache.cs - 当需要时,它检索语句以创建每个代码表的 DataSet,然后将其存储在缓存中。当只需要启用的代码表时,会在缓存的 DataSet 上使用 DataView。如果某个项目在缓存中,它将返回该值。如果不在缓存中,它将从表中生成 DataSet 并将其放入缓存。
  2. CodeTableDataSource.cs - 这是一个扩展 ObjectDataSource 的控件,可以轻松绑定到正确的代码表数据集,供 DropDownListRadioButtomList 使用。
  3. ICodeTableList.cs - 这是一个自定义类必须实现的接口,以便 CodeTableCache 可以检索简单的代码表名称及其对应的语句。

下载中还包含了一些文件,用于演示此功能

  1. CodeTableList.cs - 实现 ICodeTableList 接口的类。
  2. EditCodeTables.aspx - 用于修改代码表的网页。这有助于测试禁用的代码功能。
  3. UseCodeTable.aspx - 这是一个工作示例,其中一个表包含一个文本字段和许多代码表 ID 字段。
  4. Default.aspx - 方便访问其他两个页面。
  5. web.configglobal.asax
  6. BuildDatabase.sqlInserts.sql - SQL Server Express 脚本,用于创建此应用程序的数据库。

要使用此示例,请在 IIS 中或在 Visual Studio 的目录中进行安装。在 SQL Server 或 Express 中创建一个数据库,并执行 BuildDatabase.sqlInserts.sql 脚本来构建表。可能需要修改 web.config 中的连接字符串以访问数据库。

如果您没有 SQL Server 或 Express,可以从 Microsoft 免费下载它和 Management Studio:Microsoft SQL Server ExpressMicrosoft SQL Server Management Studio Express。我不是 SQL Server Express 用户,并且在我的一台系统上无法成功连接到服务器。如果您遇到同样的问题,请在 web.config 中为应用程序设置模拟。需要添加的节点是

<identity impersonate="true" password="win_pwd" username="machinename\winlogin" />

使用代码

在 ASPX 页面中,可以像这样简单地添加一个数据源。这些数据源用于 DropDownListRadioButtonList 的列表项。在示例中,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 添加到列表中。还记得上面的手机套餐示例吗?还需要另外两项才能使其正常工作。首先,在 GridViewDetailsViewFormView 中,将所需的列添加到 DataKey 属性。其次,在代码隐藏的 Page_Load 中,告知 CodeTableDataSource 如何查找当前选定的值。

SatisfactionVDS.DatakeyValues = TestTableDetail.DataKey.Values;
SatisfactionQDS.DatakeyValues = TestTableDetail.DataKey.Values;

这不仅限于新的 ASP.NET 2.0 GridViewDetailsViewFormView,尽管它是为它们设计的。需要做的是将 DatakeyValues 属性设置为一个 IOrderedDictionay,其键与 IdValue 属性匹配。

对于 DropDownListRadioButtonList,将 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>

如何将库集成到您的应用程序中

  1. 在应用程序中使用时,将 App_Code/OppSol 目录中的文件添加到新应用程序的同一目录中。
  2. 创建一个实现 ICodeTableList 类的类。只需要四种方法。
  3. 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 文件或单独的数据库表。

  4. 创建了 CodeTableList 类后,只需将其注册到 CodeTableCache 即可。
  5. 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();
    }
  6. 准备使用新功能所做的最后一次更改是添加 CodeTableDataSource 控件并使其在您的网页中可访问。我将其添加到了 web.config 中,但也可以在 ASPX 文件中为每个页面进行设置。

    <pages>
        <controls>
            <add namespace="OppSol.Software.CodeTableHelpers" tagPrefix="opp"/>
        </controls>
    </pages>

就是这样。希望您觉得它像我一样有用。

关注点

我在几个大型应用程序中使用了此功能的稍早版本,效果非常好。此示例使用 SQLDataSource 来处理主表,我不推荐这样做。我喜欢使用自定义业务对象,这可能是我下次集成代码表的地方。

另一个未来的增强功能可能是自定义业务对象来保存代码表数据,这将允许一些额外的功能。但目前,DataSet/DataView 组合太简单了,所以我们得拭目以待。

我最不喜欢这个解决方案的一点是需要设置 DatakeyValues 属性。我不知道有没有更优雅的方式可以从控件中获取当前绑定行中的值。您有什么想法吗?

如果您对代码表有任何想法或增强建议,请在下方的讨论中发表评论。

历史

  • 2006/10/03 - 首次修订版发布于 CodeProject。
© . All rights reserved.