A Data Access Layer to persist business objects using attributes and reflection - Part III [无常译]...
下载源代码
目录:
第一部分
第二部分
第三部分
前言
这是本系列最后一篇文章。在第一篇中我们知道了自给使用特性来给类添加声明信息。第二篇中我们已经知道如何使用System.Reflection namespace来取得声明信息。现在我们将要创建一个DAL库,可以根据任何对象自身的声明信息来实现持久化。
设计DAL库
在创建这个DAL库时,我打算将它设计成既支持SQL Serverdata provider ,也支持OldDbdata provider 。也可以扩展支持其它的data provider。我把这个库分成下面几个部分:
Utility classes
DALQueryBuilder类
在每一篇文章中已经提到过,这个类帮助构建更新对象到数据库中的SQL语句。
DALParameter类
一个普通的参数类,在存储过程中用到。
DALException类
这是一个System.Exception的派生类。在操作数据库操作出错时就会掏出此异常。我提供了有关出错的更多的信息。
Attribute 类
派生于System.Attribute 类,在第一篇中已经介绍过。
DAL itself
DALEngine 类
数据操作的抽象基类,但数据库操作更加容易。它拥有虚拟和抽象方法,不同的data provider会有不同的实现。大多的函数从数据库中返回DataSets、DataReaders,它提供方法来操作使用DAL特性标记过的对象。
DALSqlEngine 类
DALEngine的使用SQL Server的实现。
详细分析DALEngine 类
这是DALEngine类的声明:
{
//
// private data members
//
IDbConnection conn = null;
string connectionString = "";
ArrayList parameters = new ArrayList();
bool canClose = true;
// constructor
public DALEngine(string connectionString);
public bool CanClose;
public string ConnectionString;
protected IDbConnection Connection;
protected ArrayList Parameters;
public void Close();
public void Dispose();
//
// methods that must be override with a specific data provider
// implementation please see the implementation of DALSqlEngine
// or DALOleDbEngine
//
protected abstract IDbConnection GetConnection();
protected abstract IDbCommand CreateCommand(string spName);
public abstract void ExecSP_DataSet(string spName, DataSet dataSet,
string tableName);
public abstract void ExecQuery_DataSet(string query, DataSet dataSet,
string tableName);
//
// related to stored procedure parameters
//
public DALParameter GetParameter(string name);
void UpdateOutputParameters(IDbCommand cmd);
public void AddParameter(DALParameter param);
public void ClearParameters();
//
// for those that use stored procedures
//
public IDataReader ExecSP_DataReader(string spName);
public IDataReader ExecSP_DataReader(string spName,
CommandBehavior behavior);
public object ExecSP_Scalar(string spName);
public int ExecSP_NonQuery(string spName);
//
// methods for those that use plain SQL statements
//
public IDataReader ExecQuery_DataReader(string query,
CommandBehavior behavior);
public IDataReader ExecQuery_DataReader(string query);
public object ExecQuery_Scalar(string query);
public int ExecQuery_NonQuery(string query);
//
// Business objects methods
//
public static object CreateFromReader(IDataReader reader, Type objType);
public object RetrieveObject(object keyValue, Type objType);
public int RetrieveChildObjects(object foreignKeyValue, ArrayList objects,
Type childType);
void UpdateObjectSql(object o, DataTableAttribute dataTable);
void UpdateObjectStoredProcedure(object o, DataTableAttribute dataTable);
public void UpdateObject(object o);
public void UpdateObjects(IEnumerable enumObjects);
}
像你所想象中的一样,我们只需要关注最后的6个函数。其它的是很容易理解的,因为他们很容易实现。
CreateFromReader函数返回一个objType类型的对象的实例。当我们从数据库中取出数据时,就可以使用此函数来返回一个business object实例。它是一个静态函数,所以不需要建立数据库连接,只需要一个DataReader就可以读数据了。
RetrieveObject函数返回一个objType类型的对象的实例。这个实例的属性与表主键列与keyValue参数相等的唯一一行对应。这个函数在底层创建了有WHERE子句的SELECT语句。RetrieveChildObjects创建外键与foreignKeyValue 参数相等的 childType 类型的对象实例。创建的这些实体都被加到objects 参数中。
UpdateObject 和UpdateObjects 函数对数据库进行一个更新操作。更新可以使用储存过程(在此例中的类的DataTable 特性用UpdateStoreProcedure 属性来设置)或是普通SQL语句。二个私有方法UpdateObjectSql 和UpdateObjectStoredProcedure 负责执行这些更新操作。
这样做的好处
所有使用此DAL的都会使数据库编程更加容易。我强烈建议使用这个DAL,因为已经实现了重复冗长的任务,即使你没打算像我一样进行数据库编程。这次你不是必需用到,但以后至少会用到一次。
但是如果你开发数据库程序的时候用business objects ,这个库可以帮你节省很多时间和精力。这只有一个好处,就是在修改数据库时需要重新检查代码,这可以使用你自己的一个工具来完成,但利用在这篇文章的第二部分创建的工具可以完成相反的功能,即先修改business objects然后再根据business objects生成表。
为了让你更容易理解获取和更新对象,我在DAL库的代码中包含有一个样本的应用程序。这里有一些此应用程序的代码片断,你可以从中了解它的功能。
这个DAL库确实存在很多BUG,这也是我在这里发表这篇文章的原因之一。也许你会有更好的方法和代码来实现这个库的目的。有什么建议请告诉我,像我一样乐于改进这相库。
因为我要使用SQL Server,可以我从DALSqlEngine派生了一个DAL类来实现这个样板应用程序。这是我的DAL类的代码:
{
const string CONN_STRING = "server=localhost;uid=sa;pwd=;database=pubs";
public DAL() : base(CONN_STRING)
{
}
public ArrayList GetCustomerDependents(Customer customer)
{
ArrayList result = new ArrayList();
RetrieveChildObjects(customer.Id, result, typeof(CustomerDependent));
return result;
}
public void UpdateCustomerDependents(Customer customer)
{
UpdateObjects(customer.Dependents);
}
}
是不是很简单?现在是这个应用程序的代码,仅仅插入/更新了contact/customers和customer从属的对象。
{
DAL dal = new DAL();
try
{
Contact contact = new Contact();
contact.Name = "Joao Cardoso";
contact.Age = 23;
contact.Address = "Av. Rio Branco, 202/121";
contact.Address2 = "Centro";
contact.PostalCode = "09029-901";
contact.City = "Sao Paulo";
contact.State = "SP";
contact.Country = "Brazil";
dal.UpdateObject(contact);
Console.WriteLine(contact);
Contact joaoCardoso = (Contact)dal.RetrieveObject(1, typeof(Contact));
joaoCardoso.Age++;
Console.WriteLine(joaoCardoso);
Console.WriteLine("");
Customer customer = new Customer();
customer.Name = "Paul Noyter";
customer.Age = 34;
customer.Address = "All St, 2202/2121";
customer.Address2 = "Downville";
customer.PostalCode = "90931";
customer.City = "Los Angeles";
customer.State = "CA";
customer.Country = "United States";
customer.TotalPurchased += 1900.87M;
customer.NumberOfPurchases++;
dal.UpdateObject(customer);
Customer paul = (Customer)dal.RetrieveObject(1, typeof(Customer));
Console.WriteLine(paul);
paul.TotalPurchased += 100M;
paul.NumberOfPurchases++;
dal.UpdateObject(paul);
if (paul.Dependents.Count == 0)
{
CustomerDependent dependent = paul.NewDependent();
dependent.Name = "Marie Noyter";
dependent.Age = 31;
paul.Dependents.Add(dependent);
dependent = paul.NewDependent();
dependent.Name = "Mark Noyter";
dependent.Age = 10;
paul.Dependents.Add(dependent);
dependent = paul.NewDependent();
dependent.Name = "Claudia Snorg";
dependent.Age = 32;
dependent.Relationship = CustomerRelationship.Friend;
paul.Dependents.Add(dependent);
dal.UpdateCustomerDependents(paul);
}
else
{
Console.WriteLine("Dependents of {0}", paul.Name);
foreach(CustomerDependent dependent in paul.Dependents)
{
Console.WriteLine("<Dependent>{0} - {1} [{2}]", dependent.Id,
dependent.Name, dependent.Relationship);
dependent.Relationship = CustomerRelationship.Family;
}
dal.UpdateCustomerDependents(paul);
}
}
finally
{
dal.Dispose();
}
}
局限性
当然这个库也有一定的局限性。部分可以通过扩展DAL或attributes来解决。如果你不使用自动增长列,那么就必须使用存储过程来更新数据。这是因为DAL不能断定这个对象是更新还是插入到数据库。你可以扩展DAL来检测已经的特性或接口来提供需要的信息;一般不支持复合主键的表;性能要比直接使用SqlCommand要差些,但是你会有更多的时间来使用business classes替换数据库编程;我没有实现使用存储过程从数据库中检索对象,但这很容易实现。
结论
在.NET世界里,有很多途径来进行数据库编程。Visual Studio .NET允许你使用强类型的DataSet,可以节省你很多生成代码的时间。使用DataSets也一点不错,但是我更喜欢用business objects。当我开始开发这样的一样类的时间,我就可以知道写其它的类需要多长时间。这个库介绍到这里,你应该知道了怎么完善它来开发使用business objects的数据库应用程序。
---------------------------------------------------by wuchang
终于完成了这篇文章的翻译。
很多外文的文章,阅读没什么问题,意思都能看懂,但想用文字翻译流畅出来,却要费一番工夫了。
翻译得不好的地方欢迎指出。
A Data Access Layer to persist business objects using attributes and reflection - Part III [无常译]...相关推荐
- A Data Access Layer to persist business objects using attributes and reflection - Part II [无常译]...
A Data Access Layer to persist business objects using attributes and reflection - Part II By xicolok ...
- Generic Data Access Layer泛型的数据访问层
http://www.codeproject.com/Articles/630277/Generic-Data-Access-Layer-GDA-Part-I http://www.codeproje ...
- Generic Data Access Objects -范型DAO类设计模式
Generic Data Access Objects 普通数据访问对象,这个是Hibernate官方网站上面的一个DAO类的设计模式,基于JDK5.0范型支持,文章地址如下: http://www. ...
- SAP Hybris和ABAP Netweaver里的DAO(Data access object)
DAO在Hybris里的定义: A DAO (Data Access Object) is an interface to the storage back end system. DAOs stor ...
- 使用基于 Eclipse 插件框架的 ODA(Open Data Access)进行自定义数据驱动开发
ODA 之所以能够有如此强的灵活性,是因为: 它提供了一套完整的接口,开发者可以自己去实现数据源的访问逻辑,使得数据源对数据使用者变得透明.只要开发者遵循编程规范,就可以对任何数据进行驱动. 它基于 ...
- 感觉 Data Access Application Block(DAAB) 里也有可能写得不太好的地方
昨天下载了博客园的代码,里面有一个 Data\SqlServer.cs 我不清楚是不是 MS DAAB 里的原样文件.不过前面有声明如下: // =========================== ...
- 开发自己的Data Access Application Block[下篇]
上接:[原创] 我的ORM: 开发自己的Data Access Application Block - Part I 4. Database 下面来介绍重中之重:Database,绝大部分的Data ...
- Enterprise Library: Data Access Application Block配置文件分析篇
Enterprise Library: Data Access Application Block配置文件分析篇 Enterprise Library提供了Configuration Console配 ...
- Dao设计模式(Data Access Object)
目 录(本篇字数:1858) 介绍 通用Dao 一.Dao泛型接口 二.JavaBean 三.Dao接口实现类 四.单元测试 五.反射工具类 介绍 Dao设计模式(Data Access Obj ...
最新文章
- 使用Oracle 的 imp ,exp 命令实现数据的导入导出
- python批量改名_Python写个批量改名工具
- 怎么将计算机网络设置家庭,“windows无法在此计算机上设置家庭组”问题如何解决...
- 进阶的“车厘子自由”,进化的“淘宝特价版”
- beetlsql报错“请指定Sql类型“的解决方案
- 20161207py学习笔记
- ---WebCam网络摄像头7 cmos--yuv rgb , Format............:V4L2_PIX_FMT_YUYV
- Ubuntu下Python与C/C++混合编程
- java程序a-z b-y,请完成下列Java程序:对大写的26个英文字母加密,从键盘输入一个大写字母串,输出这个串加密后的结 - 赏学吧...
- 网易有数的“正确”使用方式——洞察数据中隐藏的故事
- SSH连接原理及ssh-key
- Typinator for mac(打字员)附注册码支持m1
- 上海行政区划经纬度地图_全国行政区划2017省市区完整版附经纬度及拼音
- linux加密狗复制克隆教程,Guardant Code/Guardant加密狗解密 复制 克隆 模拟
- wps分享变成小程序怎么变成文档_微信小程序使用腾讯文档打开文档
- 2017携程java后台开发工程师暑期实习生招聘面试经验分享
- JIEDU7种EMI电磁屏蔽材料介绍
- MyApps平台为政企数据保驾护航,筑牢办公安全防线
- linux 桌面 v2ex,程序员:他人笑我桌面太凌乱,我笑他人看不穿
- 调频广播如何发明的?
热门文章
- webpack 错误提示 Error: Can't resolve 'css-loader'或Error: Can't resolve 'style-loader'
- python连接redis sentinel集群
- iOS: 环信的推送
- 格密码教程(四):SVP和CVP,Hermite定理,Blichfeld定理和Minkowski定理
- Simulink之理想开关
- 51单片机按键控制数码管0~9_7种常见的51单片机时钟电路图
- 聊聊天,如果能重来,还干不干程序员?
- IDEA发布新版本,支持禅模式(免打扰)!
- 【插件发布】JAVA微服务框架,Jeecg-P3-Base-System 1.0.0 插件开源发布
- 绿色日期控件皮肤 My97 DatePicker