演练:对 LinqDataSource 控件使用时间戳以检查数据完整性
更新:2007 年 11 月
在本演练中,您将学习如何使用时间戳来检查使用 LinqDataSource 控件更新数据时的数据冲突。LinqDataSource 控件可存储网页中的时间戳值。用户更新或删除数据时,LinqDataSource 控件针对数据库中的当前时间戳值对该时间戳值进行检查。如果 LinqDataSource 控件检测到时间戳列中的值已更改,则该控件不更新或删除记录。在这种情况下,记录已由另一进程更改。LinqDataSource 控件将引发一个异常,指示记录已更改。
每次修改记录时,SQL Server 会自动更新时间戳列。有关更多信息,请参见 Timestamp (Transact-SQL)(时间戳 (Transact-SQL))。在实体类中,时间戳列是通过将 IsVersion 属性设置为 true 来进行标记的。
如果不使用时间戳列,则 LinqDataSource 控件通过存储网页中的值来检查数据并发。并发值由不同的列组成,有的用作表中的主键,有的在 ColumnAttribute 属性 (attribute) 的 UpdateCheck 属性 (property) 中标记为 UpdateCheck.Always 或 UpdateCheck.WhenUpdated。LINQ to SQL 在更新或删除数据之前针对数据库对这些值进行检查。此方法能够在数据记录包含很多列或大量列值的情况下创建大型网页。如果该记录包含您不想在页面中公开的数据,则这种方法还会带来安全风险。
您将使用对象关系设计器创建一个类,该类表示数据库表。LinqDataSource 控件将与此生成的类进行交互,以检索、更新、插入和删除数据。
先决条件
若要在您自己的开发环境中实现这些过程,您需要:
Visual Web Developer 速成版 或 Visual Studio 2008。
在计算机上安装 SQL Server Express Edition。如果已经安装了 SQL Server,则可以改用 SQL Server,但您必须对某些过程进行小的调整。
ASP.NET 网站。
创建数据库表
若要执行本演练中的步骤,必须有包含时间戳列的数据库表。如果没有这样的表,您可以执行下列过程中的步骤创建一个。如果使用现有的表,则某些过程中的步骤与数据库不完全匹配。不过,在演练中阐释的概念是相同的。
创建具有时间戳列的数据库表
如果网站上还没有 App_Data 文件夹,请在**“解决方案资源管理器”中右击相应的项目,再单击“添加 ASP.NET 文件夹”,然后单击“App_Data”**。
右击 App_Data 文件夹,然后单击**“添加新项”**。
在**“已安装的模板”下选择“SQL 数据库”,将文件名改为 Reviews.mdf,然后单击“添加”**。
在**“服务器资源管理器”中打开 Reviews.mdf 节点,然后右击“表”**文件夹。
单击**“添加新表”**。
在表中创建以下列:
列名
数据类型
属性
BookID
int
IsIdentity = Yes
不为 null
主键
Title
nvarchar(50)
Author
nvarchar(50)
RecommendToBookGroup
bit
不为 null
Review
nvarchar(1000)
Timestamp
timestamp
不为 null
保存该表并将其命名为 BookReviews。
使用示例数据将多个记录添加到 BookReviews 表。
在**“服务器资源管理器”中右击 BookReviews 表,然后单击“显示表数据”**。您不必为 BookID 或 Timestamp 指定值,因为这些值将由数据库生成。
创建表示数据库实体的类
若要使用 LinqDataSource 控件,请使用表示数据库实体的类。可以使用 Visual Web Developer 速成版或 Visual Studio 2008 中的工具创建这些类。
创建 BookReviews 表的类
如果网站上还没有 App_Code 文件夹,请在**“解决方案资源管理器”中右击相应的项目,再单击“添加 ASP.NET 文件夹”,然后单击“App_Code”**。
右击 App_Code 文件夹,然后单击**“添加新项”**。
在**“已安装的模板”下选择“Linq to SQL 类”,重命名文件 Reviews.dbml,然后单击“添加”**。
此时将显示**“对象关系设计器”**窗口。
在服务器资源管理器中,将 BookReviews 表拖入**“对象关系设计器”**窗口。
在设计器窗口中,BookReviews 表及其列以名为 BookReview 的实体表示。
保存 Reviews.dbml 文件。
在**“解决方案资源管理器”**中,打开 Reviews.designer.cs 或 Reviews.designer.vb 文件。
该实体现在具有名为 ReviewsDataContext 和 BookReview 的类。所有列的列属性都标记为 UpdateCheck=UpdateCheck.Never。但是,时间戳列的列属性用 IsVersion=true 标记。
关闭 Reviews.dbml 文件。
创建和配置 LinqDataSource 控件
现在您有了表示数据库实体的数据库表和类。您可以在 ASP.NET 网页上使用 LinqDataSource 控件管理数据的显示和更新。
创建和配置 LinqDataSource 控件
在 Visual Studio 中,创建一个新的 ASP.NET 网页,然后切换到**“源”**视图。
从**“工具箱”的“数据”**选项卡中,将 LinqDataSource 控件拖动到网页的 form 元素内。
可以将 ID 属性保留为 LinqDataSource1。
将 ContextTypeName 属性设置为 ReviewsDataContext。
将 TableName 属性设置为 BookReviews。
将 EnableUpdate 和 EnableDelete 属性设置为 true。
下面的示例演示 LinqDataSource 控件的声明性代码。
<asp:LinqDataSource ContextTypeName="ReviewsDataContext" TableName="BookReviews" EnableUpdate="true" EnableDelete="true" ID="LinqDataSource1" runat="server"> </asp:LinqDataSource>
添加显示和更新数据的控件
现在可以添加 DetailsView 控件并将其绑定到 LinqDataSource 控件。使用 DetailsView 控件,用户可以显示和更新由 LinqDataSource 控件管理的数据。
将 DetailsView 控件绑定到 LinqDataSource 控件的数据
在**“工具箱”的“数据”**选项卡中,双击 DetailsView 控件以将其添加到页面中。
可以将 ID 属性保留为 DetailsView1。
将 DataSourceID 属性设置为 LinqDataSource1。
将 DataKeyNames 属性设置为 BookID。
如果要使用 DetailsView 控件更新或删除数据,必须设置 DataKeyNames 属性。
将 AllowPaging 属性设置为 true。
将 AutoGenerateEditButton 和 AutoGenerateDeleteButton 属性设置为 true。
下面的示例演示声明性标记。
<asp:DetailsView DataSourceID="LinqDataSource1" DataKeyNames="BookID" AutoGenerateEditButton="true" AutoGenerateDeleteButton="true" AllowPaging="true" ID="DetailsView1" runat="server"> </asp:DetailsView>
在 BookReviews 数据库中,BookID 和 Timestamp 列由数据库自动设置。用户无法更改这些列的值。
保存更改。
按 Ctrl+F5 在浏览器中查看页面。
DetailsView 控件将显示 BookReviews 表中当前记录的列。
关闭浏览器。
检查数据冲突
若要了解更改数据时时间戳列如何防止更新,可以进行一个测试。在网页中选择一个要更新的记录,但在网页外对该记录进行更改。当您通过网页提交更新时,LinqDataSource 控件将会阻止更新。
测试数据完整性
按 Ctrl+F5 在浏览器中查看页面。
选择一个记录,然后单击**“编辑”**链接。先不要更新该记录。
在**“服务器资源管理器”中右击 BookReviews 表,然后单击“显示表数据”**。
更改在 Web 浏览器中打开的同一记录中的值。
关闭窗口以向数据库写入更改。
保存更改时,SQL Server 会自动更新该记录的时间戳列。
在 Web 浏览器中,更改要更新的记录中的值。
单击**“更新”**链接。
您将看到一条错误消息,指出该行已更改。保存在该页中的时间戳与数据库中该记录的时间戳不匹配。
如果要在显示此错误时执行操作,可以创建 Updating 事件的处理程序。
后续步骤
在本演练中,您已经了解了在使用 LinqDataSource 控件时如何优化数据完整性检查。通过以下方式,还可以利用 LinqDataSource 控件的其他功能:
创建一个用于处理在更改数据时所引发的异常的事件处理程序。有关更多信息,请参见 Updating 或 Deleting 事件。
筛选要返回的数据记录。如果不指定 Select 属性的值,则 LinqDataSource 控件会检索数据库表中的所有列。如果不希望在 DetailsView 控件中显示所有的列,则要选择这些列的一个子集。有关更多信息,请参见演练:使用 LinqDataSource 和 GridView 控件选择和筛选数据子集。
将数据分组以及聚合值,如计算列值的总和或平均值。有关更多信息,请参见如何:使用 LinqDataSource 控件对数据进行分组和聚合。