微软的数据库层次构架规范
为了节省你阅读微软冗长文档的时间,以下是它们关于数据层所提到的东西:CRUD和数据逻辑功能。
对于还不清楚概念的人,CRUD代表创建、读取、更新和删除。如果你从编程的角度来考虑它,那么这就是数据库所需要的所有东西。微软大力推荐的.NET构架所持的基本观点就是让数据库把自己该做的做到最好:处理好创建、维护和检索不变数据等事情。已有的许多数据库工作内容过多,因为它们具有强加上去的事务逻辑。当你把数据库层(严格)限制到CRUD时,事务逻辑就被放回到它应该在的地方了——事务逻辑层。
图A是数据层的基本构架
图A
就是这些了。如果你的数据库所包含的内容多于这些,那么你就在这一层放入了太多的东西。我想你们都知道数据库是什么,但是这个叫做数据访问逻辑组件(DALC)的东西又是什么呢?
DALC是一个典型的单一类,它对数据库里某个单一表格或者一组关系表格的数据逻辑和CRUD函数进行封装。要注意的是,这个函数可以允许少量的数据逻辑来超越CRUD。DALC允许更加明确的数据读取、更新和删除,而不是盲目地把整个数据库都读取到事务逻辑层,再在那里处理数据。
设计和创建DALC的方法有很多种。两个常用方法中的一种是使用纯量值和数据集的组合,将其作为和事务逻辑层交互操作的一种方式;方法之二是使用一个事务实体(BE)。
纯量值方法
Listing A 是DALC对简化的cmsContent表格使用纯量值和数据集的例子。(在《基于.NET的CMS数据库的两种设计方法》里,我使用的表格和这个相同,但是更加详细。)正如你能够看到的那样,这只是一个构造函数:一个用于创建、读取、更新和删除的方法。除了将这个类实例化的构造函数,这些方法每个都会执行一个CRUD函数。要是我把用于其他表格的DALC也包括进CMS数据库,你就会看到它们都会反映出和这个一样的模式。
值得注意的是,这个方法把纯量值作为参数,这个纯量值和数据里找到的数据列是对等的。它们也有同样的名称,但是这不是必须的——尽管可能会同名,因为有了它,理解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对其进行填充的过程。最后,它还有多个代表表格所有数据列的属性,这样它们就能够被创建、读取和更新。
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);
}
两种方法
现在你已经有了两种方法来访问数据库。而且,如果查看微软所提供的构架文档的话,你会发现很多其他的方法,至于使用哪种方法就由你自己来选择了。微软的构架文档应该能够帮你为开发目的而选择正确的方法。