数据访问逻辑组件(DALC)

NET Framework让软件开发人员的日子好过了不少,这在对数据库访问上的作用尤其明显。尽管做到这一点微软已经反复了好几次,但是有了ADO.NET及其分离构架和工具的便利,我认为微软终于切中了要害。在本文中,我会用自己对Microsoft所建议的.NET新构架规范的理解,说明如何为多层内容管理系统(CMS)的简化了的数据层实现代码。

微软的数据库层次构架规范

为了节省你阅读微软冗长文档的时间,以下是它们关于数据层所提到的东西:CRUD和数据逻辑功能。

对于还不清楚概念的人,CRUD代表创建、读取、更新和删除。如果你从编程的角度来考虑它,那么这就是数据库所需要的所有东西。微软大力推荐的.NET构架所持的基本观点就是让数据库把自己该做的做到最好:处理好创建、维护和检索不变数据等事情。已有的许多数据库工作内容过多,因为它们具有强加上去的事务逻辑。当你把数据库层(严格)限制到CRUD时,事务逻辑就被放回到它应该在的地方了——事务逻辑层。

图A是数据层的基本构架

图A

数据库层的基本构架


就是这些了。如果你的数据库所包含的内容多于这些,那么你就在这一层放入了太多的东西。我想你们都知道数据库是什么,但是这个叫做数据访问逻辑组件(DALC)的东西又是什么呢?

DALC是一个典型的单一类,它对数据库里某个单一表格或者一组关系表格的数据逻辑和CRUD函数进行封装。要注意的是,这个函数可以允许少量的数据逻辑来超越CRUD。DALC允许更加明确的数据读取、更新和删除,而不是盲目地把整个数据库都读取到事务逻辑层,再在那里处理数据。

设计和创建DALC的方法有很多种。两个常用方法中的一种是使用纯量值和数据集的组合,将其作为和事务逻辑层交互操作的一种方式;方法之二是使用一个事务实体(BE)。

纯量值方法

Listing A 是DALC对简化的cmsContent表格使用纯量值和数据集的例子。(在《基于.NET的CMS数据库的两种设计方法》里,我使用的表格和这个相同,但是更加详细。)正如你能够看到的那样,这只是一个构造函数:一个用于创建、读取、更新和删除的方法。除了将这个类实例化的构造函数,这些方法每个都会执行一个CRUD函数。要是我把用于其他表格的DALC也包括进CMS数据库,你就会看到它们都会反映出和这个一样的模式。

 

using System;

using System.Data;

using System.Data.SqlClient;

 

namespace DALC_Approach1

{

public class ContentDALC {

private SqlConnection m_Connection;

public ContentDALC() {

// You will want to get rid of this hard coding when you develop your own

// version of this

m_Connection = new SqlConnection("Data source=localhost;Integrated security=SSPI; Initial Catalog=CMSNET");

}

public void Create(int ContentID, string Headline, string Source, int Byline,

string Teaser, string Body, string Tagline, int Editor,

int Approver, int Status)

{

// INSERT INTO cmsContent (ContentID, Headline, Source, Byline, Teaser,

// Body, Tagline, Status, Editor, Approver,

// UpdateUserID, ModifiedDate, CreationDate)

// VALUES (@ContentID, @Headline, @Source, @Byline, @Teaser, @Body,

//         @Tagline, @Status, @Editor, @Approver, @ModifiedDate,

//         @CreationDate)

SqlCommand Command = new SqlCommand("CreateContent", m_Connection);

Command.CommandType  = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID",    SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Headline",     SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Source",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Byline",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Teaser",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Body",         SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Tagline",      SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Status",      SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Editor",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Approver",     SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@ModifiedDate", SqlDbType.DateTime));

Command.Parameters.Add(new SqlParameter("@CreationDate", SqlDbType.DateTime));

Command.Parameters["@ContentID"].Value    = ContentID;

Command.Parameters["@Headline"].Value     = Headline;

Command.Parameters["@Source"].Value       = Source;

Command.Parameters["@Byline"].Value       = Byline;

Command.Parameters["@Teaser"].Value       = Teaser;

Command.Parameters["@Body"].Value         = Body;

Command.Parameters["@Tagline"].Value      = Tagline;

Command.Parameters["@Status"].Value       = Status;

Command.Parameters["@Editor"].Value       = Editor;

Command.Parameters["@Approver"].Value     = Approver;

Command.Parameters["@ModifiedDate"].Value = DateTime.Now;

Command.Parameters["@CreationDate"].Value = DateTime.Now;

try {

m_Connection.Open();

Command.ExecuteNonQuery();

} finally {

m_Connection.Close();

} }

public DataSet Read(int ContentID) {

// SELECT ContentID, Headline, Source, Byline, Teaser, Body, Tagline,

// Status, Editor, Approver, ModifiedDate, CreationDate

//  FROM  cmsContent

// WHERE (ContentID = @ContentID)

SqlCommand Command = new SqlCommand("ReadContent", m_Connection);

Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID", SqlDbType.Int));

Command.Parameters["@ContentID"].Value = ContentID;

SqlDataAdapter DAdpt = new SqlDataAdapter(Command);

DataSet ds = new DataSet();

DAdpt.Fill(ds, "Content");

return ds;

}

public void Update(int ContentID, string Headline, string Source, int Byline,

string Teaser, string Body, string Tagline, int Editor,

int Approver, int Status)

{

// UPDATE cmsContent

// SET

//        Headline     = @Headline,

//        Source       = @Source,

//        Byline       = @Byline,

//        Teaser       = @Teaser,

//        Body         = @Body,

//        Tagline      = @Tagline,

//        Status       = @Status,

//        Editor       = @Editor,

//        Approver     = @Approver,

//        ModifiedDate = @ModifiedDate

// WHERE  (ContentID = @ContentID)

SqlCommand Command = new SqlCommand("UpdateContent", m_Connection);

Command.CommandType  = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID",    SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Headline",     SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Source",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Byline",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Teaser",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Body",         SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Tagline",      SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Status",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Editor",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Approver",     SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@ModifiedDate", SqlDbType.DateTime));

Command.Parameters["@ContentID"].Value    = ContentID;

Command.Parameters["@Headline"].Value     = Headline;

Command.Parameters["@Source"].Value       = Source;

Command.Parameters["@Byline"].Value       = Byline;

Command.Parameters["@Teaser"].Value       = Teaser;

Command.Parameters["@Body"].Value         = Body;

Command.Parameters["@Tagline"].Value      = Tagline;

Command.Parameters["@Status"].Value       = Status;

Command.Parameters["@Editor"].Value       = Editor;

Command.Parameters["@Approver"].Value     = Approver;

Command.Parameters["@ModifiedDate"].Value = DateTime.Now;

try {

m_Connection.Open();

Command.ExecuteNonQuery();

} finally {

m_Connection.Close();

} }

public void Delete(int ContentID) {

// DELETE FROM cmsContent

// WHERE (ContentID = @ContentID)

SqlCommand Command = new SqlCommand("DeleteContent", m_Connection);

Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID", SqlDbType.Int));

Command.Parameters["@ContentID"].Value = ContentID;

try {

m_Connection.Open();

Command.ExecuteNonQuery();

} finally {

m_Connection.Close();

} } } }

值得注意的是,这个方法把纯量值作为参数,这个纯量值和数据里找到的数据列是对等的。它们也有同样的名称,但是这不是必须的——尽管可能会同名,因为有了它,理解DALC和数据库之间的映射会更加容易一些。

只有读取方法会把数据返回给事务逻辑层,而且它是通用数据集的形式完成的。数据集里的数据是由事务逻辑层的逻辑来处理的。这种方法真正执行的只是CRUD功能。像下面这样就能实现这种方法:

static void Main(string[] args){
// Create a ContentDALC object
ContentDALC DALC = new ContentDALC();
// Get Content for ID 1234
DataSet ds = DALC.Read(1234);
Console.WriteLine("Content Body: {0}",
ds.Tables["Content"].Rows[0]["Body"]);
}

 

事务实体方法

第二种方法涉及事务实体。微软定义了实现事务逻辑的多种方式。在CMS的情况下,我使用这个定义:事务实体是一个面向对象的类,它代表着数据库表格或者查看表的一个单行。听起来很像DALC,对吧?但是它们之间一个巨大的不同是:这是一个事务逻辑层对象;它并不真正地同数据库进行直接的交互操作。

让我们来看看BE。正如你会在Listing B(对于这个例子,我再次使用了简化的cmsContent表格)里的那样,这差不多是个简化版本的BE,因为它在确认方面做得不多,属性和方法的数量也是有限的。BE包含有三个构造函数。第一个是缺省的;第二个把表格键(用于读取和删除)作为参数;第三个用于接纳表格的所有数据列(在创建和更新时会用到)。BE包含了一个方法,用来简化DALC对其进行填充的过程。最后,它还有多个代表表格所有数据列的属性,这样它们就能够被创建、读取和更新。

using System;

using System.Data;

namespace BEs

{

public class ContentBE  {

private int      mContentID;

private string   mHeadline;

private string   mSource;

private int      mByline;

private string   mTeaser;

private string   mBody;

private string   mTagline;

private int      mStatus;

private int      mEditor;

private int      mApprover;

private DateTime mModifiedDate;

private DateTime mCreationDate;

private bool mInitialized;

public ContentBE() {

Initialized = false;

}

public ContentBE(int inContentID) {

ContentID = inContentID;

Initialized = false;

}

public ContentBE(int inContentID, string inHeadline, string inSource,

int inByline, string inTeaser, string inBody, string inTagline,

int inEditor, int inApprover, int inStatus) {

ContentID = inContentID;

Headline = inHeadline;

Source = inSource;

Byline = inByline;

Teaser = inTeaser;

Body = inBody;

Tagline = inTagline;

Status = inStatus;

Editor = inEditor;

Approver = inApprover;

Initialized = true;

}

public void BuildFromDALC(DataRow dr) {

ContentID = Convert.ToInt32(dr["ContentID"]);

Headline = dr["Headline"].ToString();

Source = dr["Source"].ToString();

Byline = Convert.ToInt32(dr["Byline"]);

Teaser = dr["Teaser"].ToString();

Body = dr["Body"].ToString();

Tagline = dr["TagLine"].ToString();

Status = Convert.ToInt32(dr["Status"]);

Editor = Convert.ToInt32(dr["Editor"]);

Approver = Convert.ToInt32(dr["Approver"]);

ModifiedDate = Convert.ToDateTime(dr["ModifiedDate"]);

CreationDate = Convert.ToDateTime(dr["CreationDate"]);

Initialized = true;

}

public int ContentID {

get { return mContentID;  }

set { mContentID = value; }

}

public string Headline {

get { return mHeadline;  }

set { mHeadline = value; }

}

public string Source {

get { return mSource;  }

set { mSource = value; }

}

public int Byline {

get { return mByline;  }

set { mByline = value; }

}

public string Teaser {

get { return mTeaser;  }

set { mTeaser = value; }

}

public string Body {

get { return mBody;  }

set { mBody = value; }

}

public string Tagline {

get { return mTagline;  }

set { mTagline = value; }

}

public int Status {

get { return mStatus;  }

set { mStatus = value; }

}

public int Editor {

get { return mEditor;  }

set { mEditor = value; }

}

public int Approver {

get { return mApprover;  }

set { mApprover = value; }

}

public DateTime ModifiedDate {

get { return mModifiedDate;  }

set { mModifiedDate = value; }

}

public DateTime CreationDate {

get { return mCreationDate;  }

set { mCreationDate = value; }

}

public bool Initialized {

get { return mInitialized;  }

set { mInitialized = value; }

} } }

Listing C显示的是如何改变DALC,让其能够和BE一起工作。事实上,对于DALC,传递BE只不过简化了它的参数表。另一方面,对于要使用和这个DALC相关联的数据的开发人员来说,情况会稍稍容易和安全一点,因为现在表格能够像对象一样被操控,就像下面这样:

using System;

using System.Data;

using System.Data.SqlClient;

 

using BEs;

 

namespace DALC_Approach2

{

public class ContentDALC {

private SqlConnection m_Connection;

 

public ContentDALC() {

// You will want to get rid of this hard coding when you develop your own

// version of this

m_Connection = new SqlConnection("Data source=localhost;Integrated security=SSPI; Initial Catalog=CMSNET");

}

 

public void Create(ContentBE cBE) {

// INSERT INTO cmsContent (ContentID, Headline, Source, Byline, Teaser,

//                        Body, Tagline, Status, Editor, Approver,

//                         UpdateUserID, ModifiedDate, CreationDate)

// VALUES (@ContentID, @Headline, @Source, @Byline, @Teaser, @Body,

//         @Tagline, @Status, @Editor, @Approver, @ModifiedDate,

//         @CreationDate)

 

if (!cBE.Initialized)

throw new ApplicationException("Content Business Entity not initialized");

 

SqlCommand Command = new SqlCommand("CreateContent", m_Connection);

Command.CommandType  = CommandType.StoredProcedure;

           

Command.Parameters.Add(new SqlParameter("@ContentID",    SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Headline",     SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Source",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Byline",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Teaser",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Body",         SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Tagline",      SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Status",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Editor",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Approver",     SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@ModifiedDate", SqlDbType.DateTime));

Command.Parameters.Add(new SqlParameter("@CreationDate", SqlDbType.DateTime));

 

Command.Parameters["@ContentID"].Value    = cBE.ContentID;

Command.Parameters["@Headline"].Value     = cBE.Headline;

Command.Parameters["@Source"].Value       = cBE.Source;

Command.Parameters["@Byline"].Value       = cBE.Byline;

Command.Parameters["@Teaser"].Value       = cBE.Teaser;

Command.Parameters["@Body"].Value         = cBE.Body;

Command.Parameters["@Tagline"].Value      = cBE.Tagline;

Command.Parameters["@Status"].Value       = cBE.Status;

Command.Parameters["@Editor"].Value       = cBE.Editor;

Command.Parameters["@Approver"].Value     = cBE.Approver;

Command.Parameters["@ModifiedDate"].Value = DateTime.Now;

Command.Parameters["@CreationDate"].Value = DateTime.Now;

 

try {

m_Connection.Open();

Command.ExecuteNonQuery();

} finally {

m_Connection.Close();

} }

 

public ContentBE Read(ContentBE cBE)

{

// SELECT ContentID, Headline, Source, Byline, Teaser, Body, Tagline,

//        Status, Editor, Approver, ModifiedDate, CreationDate

//  FROM  cmsContent<BR>

// WHERE (ContentID = @ContentID)

 

if (cBE.ContentID <= 0)

throw new ApplicationException("Content Business Entity ID not specified");

 

SqlCommand Command = new SqlCommand("ReadContent", m_Connection);

Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID", SqlDbType.Int));

Command.Parameters["@ContentID"].Value = cBE.ContentID;

 

SqlDataAdapter DAdpt = new SqlDataAdapter(Command);

 

DataSet ds = new DataSet();

DAdpt.Fill(ds, "Content");

 

if (ds.Tables["Content"].Rows.Count > 0)

cBE.BuildFromDALC(ds.Tables["Content"].Rows[0]);

else

throw new ApplicationException("No Content found for ID");

return cBE;

}

 

public void Update(ContentBE cBE) {

// UPDATE cmsContent

// SET

//        Headline     = @Headline,

//        Source       = @Source,

//        Byline       = @Byline,

//        Teaser       = @Teaser,

//        Body         = @Body,

//        Tagline      = @Tagline,

//        Status       = @Status,

//        Editor       = @Editor,

//        Approver     = @Approver,

//        ModifiedDate = @ModifiedDate

// WHERE  (ContentID = @ContentID)

 

SqlCommand Command = new SqlCommand("UpdateContent", m_Connection);

Command.CommandType  = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID",    SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Headline",     SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Source",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Byline",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Teaser",       SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Body",         SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Tagline",      SqlDbType.Text));

Command.Parameters.Add(new SqlParameter("@Status",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Editor",       SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Approver",     SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@ModifiedDate", SqlDbType.DateTime));

Command.Parameters["@ContentID"].Value    = cBE.ContentID;

Command.Parameters["@Headline"].Value     = cBE.Headline;

Command.Parameters["@Source"].Value       = cBE.Source;

Command.Parameters["@Byline"].Value       = cBE.Byline;

Command.Parameters["@Teaser"].Value       = cBE.Teaser;

Command.Parameters["@Body"].Value         = cBE.Body;

Command.Parameters["@Tagline"].Value      = cBE.Tagline;

Command.Parameters["@Status"].Value       = cBE.Status;

Command.Parameters["@Editor"].Value       = cBE.Editor;

Command.Parameters["@Approver"].Value     = cBE.Approver;

Command.Parameters["@ModifiedDate"].Value = DateTime.Now;

try {

m_Connection.Open();

Command.ExecuteNonQuery();

} finally {

m_Connection.Close();

} }

public void Delete(ContentBE cBE) {

// DELETE FROM cmsContent

// WHERE (ContentID = @ContentID)

SqlCommand Command = new SqlCommand("DeleteContent", m_Connection);

Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@ContentID", SqlDbType.Int));

Command.Parameters["@ContentID"].Value = cBE.ContentID;

try {

m_Connection.Open();

Command.ExecuteNonQuery();

}

finally {

m_Connection.Close();

} } } }

static void Main(string[] args) {
// Create a ContentDALC object
ContentDALC DALC = new ContentDALC();
// Create a ContentBE
ContentBE BE = new ContentBE(1234);
// Get Content for ID 1234
DALC.Read(BE);
Console.WriteLine("Content Body: {0}", BE.Body);
}
 

两种方法

现在你已经有了两种方法来访问数据库。而且,如果查看微软所提供的构架文档的话,你会发现很多其他的方法,至于使用哪种方法就由你自己来选择了。微软的构架文档应该能够帮你为开发目的而选择正确的方法。

posted on 2005-11-17 11:55  黑月  阅读(728)  评论(0编辑  收藏  举报

导航