|
例就是返回一个基于某个键的实体,例如基于
userId 的用户:''''Visual Basic .NET
Public Function FindUserById(ByVal userId As Integer) As User
For Each user As User In List
If user.UserId = userId Then
Return user
End If
Next
Return Nothing
End Function
//C#
public User FindUserById(int userId) {
foreach (User user in List) {
if (user.UserId == userId){
return user;
}
}
return null;
}
另一个示例可能是返回基于特定标准(例如部分用户名)的用户子集: ''''Visual Basic .NET
Public Function FindMatchingUsers(ByVal search As String) As UserCollection
If search Is Nothing Then
Throw New ArgumentNullException("search cannot be null")
End If
Dim matchingUsers As New UserCollection
For Each user As User In List
Dim userName As String = user.UserName
If Not userName Is Nothing And userName.StartsWith(search) Then
matchingUsers.Add(user)
End If
Next
Return matchingUsers
End Function
//C#
public UserCollection FindMatchingUsers(string search) {
if (search == null){
throw new ArgumentNullException("search cannot be null");
}
UserCollection matchingUsers = new UserCollection();
foreach (User user in List) {
string userName = user.UserName;
if (userName != null && userName.StartsWith(search)){
matchingUsers.Add(user);
}
}
return matchingUsers;
}
可以通过 DataTable.Select 以相同的方式使用
DataSets。需要说明的重要一点是,尽管创建自己的功能使您可以完全控制您的代码,但
Select
方法为完成同样的操作提供了一个非常方便且不需要编写代码的方法。但另一方面,Select
需要开发人员了解基础数据库,而且它不是强类型。
绑定自定义集合
我们看到的第一个示例是将 DataSet 绑定到 ASP.NET
控件。考虑到它很普通,您会高兴地发现自定义集合绑定同样很简单(这是因为 CollectionBase 实现了用于绑定的
Ilist)。自定义集合可以作为任何控件的 DataSource,而
DataBinder.Eval 只能像您使用 DataSet 那样使用: ''''Visual Basic .NET
Dim users as UserCollection = DAL.GetallUsers()
repeater.DataSource = users
repeater.DataBind()
//C#
UserCollection users = DAL.GetAllUsers();
repeater.DataSource = users;
repeater.DataBind();
<!-- HTML -->
<asp:Repeater onItemDataBound="r_IDB" ID="repeater" Runat="server">
<ItemTemplate>
<asp:Label ID="userName" Runat="server">
<%# DataBinder.Eval(Container.DataItem, "UserName") %><br />
</asp:Label>
</ItemTemplate>
</asp:Repeater>
您可以不使用列名称作为 DataBinder.Eval 的第二个参数,而指定您希望显示的属性名称,在本例中为
UserName。
对于在许多数据绑定控件提供的 OnItemDataBound 或
OnItemCreated 中执行处理的人来说,您可能会将 e.Item.DataItem
强制转换成 DataRowView。当绑定到自定义集合时,e.Item.DataItem
则被强制转换成自定义实体,在我们的示例中为 User 类: ''''Visual Basic .NET
Protected Sub r_ItemDataBound (s As Object, e As RepeaterItemEventArgs)
Dim type As ListItemType = e.Item.ItemType
If type = ListItemType.AlternatingItem OrElse
? type = ListItemType.Item Then
Dim u As Label = CType(e.Item.FindControl("userName"), Label)
Dim currentUser As User = CType(e.Item.DataItem, User)
If Not PasswordUtility.PasswordIsSecure(currentUser.Password) Then
ul.ForeColor = Drawing.Color.Red
End If
End If
End Sub
//C#
protected void r_ItemDataBound(object sender, RepeaterItemEventArgs e) {
ListItemType type = e.Item.ItemType;
if (type == ListItemType.AlternatingItem ||
? type == ListItemType.Item){
Label ul = (Label)e.Item.FindControl("userName");
User currentUser = (User)e.Item.DataItem;
if (!PasswordUtility.PasswordIsSecure(currentUser.Password)){
ul.ForeColor = Color.Red;
}
}
}
返回页首
管理关系
即使在最简单的系统中,实体之间也存在关系。对于关系数据库,可以通过外键维护关系;而使用对象时,关系只是对另一个对象的引用。例如,根据我们前面的示例,User
对象完全可以具有一个 Role: ''''Visual Basic .NET
Public Class User
Private _role As Role
Public Property Role() As Role
Get
Return _role
End Get
Set(ByVal Value As Role)
_role = Value
End Set
End Property
End Class
//C#
public class User {
private Role role;
public Role Role {
get {return role;}
set {role = value;}
}
}
或者一个 Role 集合: ''''Visual Basic .NET
Public Class User
Private _roles As RoleCollection
Public ReadOnly Property Roles() As RoleCollection
Get
If _roles Is Nothing Then
_roles = New RoleCollection
End If
Return _roles
End Get
End Property
End Class
//C#
public class User {
private RoleCollection roles;
public RoleCollection Roles {
get {
if (roles == null){
roles = new RoleCollection();
}
return roles;
}
}
}
在这两个示例中,我们有一个虚构的 Role 类或 RoleCollection
类,它们就是类似于 User 和 UserCollection
类的其他自定义实体或集合类。
映射关系
真正的问题在于如何映射关系。让我们看一个简单的示例,我们希望根据 userId
及其角色来检索一个用户。首先,我们看一看关系模型:

图
3:User 与
Role 之间的关系
这里,我们看到了一个 User 表和一个 Role
表,我们可以将这两个表都以直观的方式映射到自定义实体。我们还有一个 UserRoleJoin 表,它代表了
User 与 Role 之间的多对多关系。
然后,我们使用存储过程来获取两个单独的结果:第一个代表 User,第二个代表该用户的
Role: CREATE PROCEDURE GetUserById(
@UserId INT
)AS
SELECT UserId, UserName, [Password]
FROM Users
WHERE UserId = @UserID
SELECT R.RoleId, R.[Name], R.Code
FROM Roles R INNER JOIN
UserRoleJoin URJ ON R.RoleId = URJ.RoleId
WHERE URJ.UserId = @UserId
最后,我们从关系模型映射到对象模型: ''''Visual Basic .NET
Public Function GetUserById(ByVal userId As Integer) As User
Dim connection As New SqlConnection(CONNECTION_STRING)
Dim command As New SqlCommand("GetUserById", connection)
command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId
Dim dr As SqlDataReader = Nothing
Try
connection.Open()
dr = command.ExecuteReader()
Dim user As User = Nothing
If dr.Read() Then
user = PopulateUser(dr)
dr.NextResult()
While dr.Read()
user.Roles.Add(PopulateRole(dr))
End While
End If
Return user
Finally
If Not dr Is Nothing AndAlso Not dr.IsClosed Then
dr.Close()
End If
connection.Dispose()
command.Dispose()
End Try
End Function
//C#
public User GetUserById(int userId) {
SqlConnection connection = new SqlConnection(CONNECTION_STRING);
SqlCommand command = new SqlCommand("GetUserById", connection);
command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId;
SqlDataReader dr = null;
try{
connection.Open();
dr = command.ExecuteReader();
User user = null;
if (dr.Read()){
user = PopulateUser(dr);
dr.NextResult();
while(dr.Read()){
user.Roles.Add(PopulateRole(dr));
}
}
return user;
}finally{
if (dr != null && !dr.IsClosed){
dr.Close();
}
connection.Dispose();
command.Dispose();
}
}
User 实例即被创建和填充;我们转移到下一个结果/选择并进行循环,填充 Role
并将它们添加到 User 类的 RolesCollection 属性中。
返回页首
高级内容
本指南的目的是介绍自定义实体与集合的概念及使用。使用自定义实体是业界广泛采用的做法,因此,也就产生了同样多的模式以处理各种情况。设计模式具有优势的原因有很多。首先,在处理具体的情况时,您可能不是第一次碰到某个给定的问题。设计模式使您可以重新使用给定问题的已经过尝试和测试的解决方案(虽然设计模式并不意味着全盘照抄,但它们几乎总是能够为解决方案提供一个可靠的基础)。相应地,这使您对系统随着复杂性增加而进行缩放的能力充满了信心,不仅因为它是一个广泛使用的方法,还因为它具有详尽的记录。设计模式还为您提供了一个通用的词汇表,使知识的传播和传授更容易实现。
不能说设计模式只适用于自定义实体,实际上许多设计模式都并非如此。但是,如果您找机会试一下,您可能会惊喜地发现许多记载详尽的模式确实适用于自定义实体和映射过程。
最后这一部分专门介绍大型或较复杂的系统可能会碰到的一些高级情况。因为大多数主题都可能值得您单独学习,所以我会尽量为您提供一些入门资料。
Martin Fowler 的 Patterns of Enterprise Application
Architecture
就是一个很好的入门材料,它不仅可以作为常见设计模式的优秀参考(具有详细的解释和大量的示例代码),而且它的前 100
页确实可以让您透彻地了解整个概念。另外,Fowler 还提供了一个联机模式目录,它对于已经熟悉概念但需要一个便利参考的人士很有用。
并发
前面的示例介绍的都是从数据库中提取数据并根据这些数据创建对象。总体而言,更新、删除和插入数据等操作是很直观的。我们的业务层负责创建对象、将对象传递给数据访问层,然后让数据访问层处理对象世界与关系世界之间的映射。例如: ''''Visual Basic .NET
Public sub UpdateUser(ByVal user As User)
Dim connection As New SqlConnection(CONNECTION_STRING)
Dim command As New SqlCommand("UpdateUser", connection)
'''' 可以借助可重新使用的函数对此进行反向映射
command.Parameters.Add("@UserId", SqlDbType.Int)
command.Parameters(0).Value = user.UserId
command.Parameters.Add("@Password", SqlDbType.VarChar, 64)
command.Parameters(1).Value = user.Password
command.Parameters.Add("@UserName", SqlDbType.VarChar, 128)
command.Parameters(2).Value = user.UserName
Try
connection.Open()
command.ExecuteNonQuery()
Finally
connection.Dispose()
command.Dispose()
End Try
End Sub
//C#
public void UpdateUser(User user) {
SqlConnection connection = new SqlConnection(CONNECTION_STRING);
SqlCommand command = new SqlCommand("UpdateUser", connection);
// 可以借助可重新使用的函数对此进行反向映射
command.Parameters.Add("@UserId", SqlDbType.Int);
command.Parameters[0].Value = user.UserId;
command.Parameters.Add("@Password", SqlDbType.VarChar, 64);
command.Parameters[1].Value = user.Password;
command.Parameters.Add("@UserName", SqlDbType.VarChar, 128);
command.Parameters[2].Value = user.UserName;
try{
connection.Open();
command.ExecuteNonQuery();
}finally{
connection.Dispose();
command.Dispose();
}
}
但在处理并发时就不那么直观了,也就是说,当两个用户试图同时更新相同的数据时会出现什么情况呢?默认的行为(如果您没有执行任何操作)是最后提交数据的人将覆盖以前所有的工作。这可能不是理想的情况,因为一个用户的工作将在未获得任何提示的情况下被覆盖。要完全避免所有冲突,一种方法就是使用消极的并发技术;但此方法需要具有某种锁定机制,这可能很难通过可缩放的方式实现。替代方法就是使用积极的并发技术。让第一个提交的用户控制并通知后面的用户是通常采取的更温和、更用户友好的方法。这可以通过某种行版本控制(例如时间戳)来实现。
参考资料:
?
Introduction to Data Concurrency in ADO.NET 上一页 [1] [2] [3] [4] 下一页 [C语言系列]NET 中C#的switch语句的语法 [网页制作]需要掌握的八个CSS网页布局技巧! [办公软件]掌握Excel十二条操作技巧,让工作更效益 [办公软件]喧宾不夺主—轻松掌握Word对象的叠放次序 [办公软件]掌握Word英文大小写转换,提高工作效益 [操作系统]全方位掌握系统自动更新的设置 [操作系统]掌握基本输入输出系统CMOS的使用及维护知识 [操作系统]轻松掌握10个Windows2003的配置技巧下篇 [操作系统]轻松掌握10个Windows2003的配置技巧上篇 [网络技术]让DHCP服务器不再是累赘就得掌握使用方法和技巧中…
|