数据访问层(ASP.NET 3.5 Enterprise Application Development)读书笔记
-- Problem – Design – Solution
本文是针对Wrox出版的《ASP.NET 3.5 Enterprise Application Development With Visual Studio 2008 Problem Design Solution》该书第二章Data Access Layer(数据访问层)读书笔记。
http://forum.EntLib.com 开源论坛小组提供,欢迎交流,分享。
原文介绍在三层架构应用中使用 LINQ to SQL技术。该设计模式使用DataContext 和数据库交互,ORM Designer设计器生成的实体对象(Entity Object)则负责与BLL(业务逻辑层)交互。
该架构的设计图如下所示:
在原文中通过将存储过程拖拉到ORM 设计器中,并使用存储过程来访问数据,如Insert、Update、Delete、Select等等方法。如下图所示:
将Method Panel中的方法与ORM 设计器中实体对象进行的关联的步骤如下。
首先,选择ORM 设计器中的实体对象,如上图中的ENTUserAccount。
然后,查看属性列表,比如点击Insert 属性后的弹出按钮,弹出如下对话框。
经过上述设置后,DataContext 将调用存储过程来插入记录,而不是想之前的创建动态的SQL脚本。在DBML自动创建的cs文件中,可以看到如下2个方法:
private void InsertENTUserAccount(ENTUserAccount obj)
{
System.Nullable<int> p1 = obj.ENTUserAccountId;
this.ENTUserAccountInsert(ref p1, obj.WindowsAccountName, obj.FirstName, obj.LastName, obj.Email, ((System.Nullable<bool>)(obj.IsActive)), ((System.Nullable<int>)(obj.InsertENTUserAccountId)));
obj.ENTUserAccountId = p1.GetValueOrDefault();
}
[Function(Name="dbo.ENTUserAccountInsert")]
public int ENTUserAccountInsert([Parameter(Name="ENTUserAccountId", DbType="Int")] ref System.Nullable<int> eNTUserAccountId, [Parameter(Name="WindowsAccountName", DbType="VarChar(50)")] string windowsAccountName, [Parameter(Name="FirstName", DbType="VarChar(50)")] string firstName, [Parameter(Name="LastName", DbType="VarChar(50)")] string lastName, [Parameter(Name="Email", DbType="VarChar(100)")] string email, [Parameter(Name="IsActive", DbType="Bit")] System.Nullable<bool> isActive, [Parameter(Name="InsertENTUserAccountId", DbType="Int")] System.Nullable<int> insertENTUserAccountId)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), eNTUserAccountId, windowsAccountName, firstName, lastName, email, isActive, insertENTUserAccountId);
eNTUserAccountId = ((System.Nullable<int>)(result.GetParameterValue(0)));
return ((int)(result.ReturnValue));
}
其中第一个方法接收一个ENTUserAccount 对象的参数,并调用第二个方法,将对象的属性作为参数传入。第二个方法接收存储过程的每一个参数,接着调用DataContext对象的ExecuteMethodCall方法,该方法知道如何调用存储过程,并返回结果。
另外的Delete、Update属性操作相似。操作完成后,ENTUserAccount 实体对象的属性列表如下所示:
客户端调用的示例代码如下:
//Create an instance of the data context
HRPaidTimeOffDataContext db = new HRPaidTimeOffDataContext();
//Create a new ENTUserAccount object and set the properties
ENTUserAccount userAccount = new ENTUserAccount
{
WindowsAccountName = @”VARALLO1\VaralloMadison”,
FirstName = “Madison”,
LastName = “Varallo”,
Email = “madison.varallo@v2.com”,
IsActive = true,
InsertDate = DateTime.Now,
InsertENTUserAccountId = 1,
UpdateDate = DateTime.Now,
UpdateENTUserAccountId = 1
};
//Signal the context to insert this record
db.ENTUserAccounts.InsertOnSubmit(userAccount);
//Save the changes to the database
db.SubmitChanges();
为什么要这样设计呢?我不是很认同这种设计。
1. 任何对表ENTUserAccount的修改,都需要重新将EntUserAccount表拖拉到ORM设计器中,并重新设置Insert、Update、Delete 等等属性。
2. 需要编写很多琐碎的存储过程,如上述的Insert、Update、Delete、Select等等,相信很多开发人员不喜欢编写这么多简单的Stored Procedure。
3. 这样设计增加很多工作量,并且不便于后期的维护开发,也影响工作效率。
本章后面部分定义的一些接口类、抽象基类是针对该项目设计的特性提取的一些共用特征。这种设计方法值得推荐,但并不一定适合于实际的开发项目。
public interface IENTBaseEntity
public abstract class ENTBaseData<T> where T : IENTBaseEntity
在数据访问层DAL仅仅只有2个上述的基类。
public class ENTUserAccountData : ENTBaseData<ENTUserAccount>
上述的Data类封装出来ENTUserAccount实体对象,ENTUserAccountData类继承自ENTBaseData基类,实现基类中的抽象方法。
ORM设计器负责为数据库中每一个表生成一个对应的实体类,对应Data类则负责与数据库和业务逻辑层交互。
下一篇是关于业务逻辑层BLL的设计探讨。