PetShop.NET有感

[注]:当时PetShop.NET 3.0出来时就整理的一份资料,之前硬盘被感染病毒遭破坏,后来恢复了点过来,近期有空稍微整理了下那些恢复过来的资料,发现有这么一份当时模仿PetShop.NET 3.0写的代码项目,于是稍微整理了下弄成资料放上来。时间久了,之间可能有理解偏差或比较欠缺的地方,还望大家指正。

一、项目前言

PetShop实现了什么业务功能,我想不用我多说。自从Sun弄了个PetStore作为Java经典范例后,似乎有点演变成为“Hello World”的趋势,只不过对PetShop来说,我想微软的意图跟Sun一样,都偏重架构与模式上的应用。PetShop.NET至今最新版本还是3.0版本,我想这个版本跟2.0差别比较大,一安装从解决方案里的11个项目就看出点苗头了。PetShop.NET 3.0通过编写相应的数据访问逻辑,然后简单修改配置文件web.config实现替换后台数据库系统的功能,在这个主题功能后面,它主要是用了.NET里的反射结合工厂模式来实现该功能。当时看完后,一时兴起,自己模仿它也弄了个只有一个表(2个字段)的很简单的模型。源代码可以从这里载[下载]。

二、项目结构

该解决方案名为DataChangeSample,一共含8个项目,每个项目都有它自己存在的一个主要目的,8个项目通过自身的主要作用互相结合联系在一起组合成了该解决方案的功能。项目结构图如下:

IDAL:意思为 Interface Data Access Logic,数据访问逻辑接口。其下有AccessDAL、OracleDAL与SqlServerDAL实现了其接口,针对每种数据库系统编写的数据访问逻辑都要实现该接口。
AccessDAL:专门针对Access小型数据库编写的数据访问逻辑,实现了IDAL接口。
OracleDAL:专门针对Oracle编写的数据访问逻辑,实现了IDAL接口。
SqlServerDAL:专门针对SQLServer编写的数据访问逻辑,实现了IDAL接口。
DALFactory:数据访问逻辑工厂,由该工厂负责根据配置文件动态创建系统所需的数据访问逻辑对象。
BizEntity:业务实体,实质为数据库表的抽象类。
BizRule:业务规则。
Web:表现层。因为只为演示,只提供一个增加操作。

三、组件图与工厂模式图:


四、项目安装说明

项目解压缩到根目录后,设置Web目录为Web共享即可。将Web.config文件里相应参数配置下,修改节点的value值为数据访问逻辑的程序集名为你当前所要的数据库访问逻辑程序集名,运行即可。

五、总结

整体感觉,整个结构还是挺清晰的。有一点严重不足的是针对每种数据库都要重新编写访问逻辑与访问帮助类。后来看了孙亚民先生的文章后有点启发,能不能把这些信息都通过XML文件保存,然后通过类似他的WebSharp中间件进行开发,会不会更加简单?这点我没有实现,不过我想应该是可以的吧。不知道下个版本的PetShop又要给我们带来什么样的架构和模式参考呢?

This entry was posted in 未分类. Bookmark the permalink.

17 Responses to PetShop.NET有感

  1. 东方蜘蛛 says:

    CODEPROJECT有一个基于XML的DAL,写的很不错的

    [回复]

  2. dreamriver says:

    这种动态加载,效率应该很高的。特别是在多层应用中实现层之间传递较大的数据对象时,我想应该比用xml优势明显。

    [回复]

  3. dreamriver says:

    在php开发中有一个比较完善的数据操作类库,叫ADODB。支持任何类型的DBMS。这个类库的用法就是在系统配置页中指定数据库类型、数据库名称、用户名、口令。然后在每一个需要操作数据库的页面中先初始化对象,然后调用Execute(string SQLStr)方法。就可以返回一个数据集。然后再程序逻辑中对这个数据集进行操作。使用非常方便。
    我的设想是,如果将PetShop.IDAL 数据访问接口再往下移一层。因为无论DBMS是什吗类型,业务逻辑都是相同的。只有在业务逻辑需要最后操作数据库时再进行面向接口的数据库操作。也就是说将IDAL类变成IDABB。并实现这样几个接口:
    IExecuteNoeQuery(string,CommandType,string, params SqlParameter[]);
    IExecuteReader(string,CommandType,string, params SqlParameter[]);
    IExecuteScalar(string,CommandType,string, params SqlParameter[]);
    ICatchParameters(string, params SqlParameter[]);
    这样的话,就避免了针对每种数据库都要重新编写访问逻辑与访问帮助类的缺点。岂不妙哉!

    [回复]

  4. coollzh says:

    dreamriver 你这个需求早就有人事先了
    DAAB3.0上就实现了,去gotdotnet上down吧,我上个项目就是用的它

    [回复]

  5. 云舒 says:

    你好,你的代码不能下载,能否更新连接?
    你的blog我收藏了
    :)

    [回复]

  6. PNET says:

    代码不能下载,能否更新连接

    [回复]

  7. 云舒 says:

    哈,不用下载了
    petshop和那个Duwamish7基本看明白了

    [回复]

  8. unrealwalker says:

    M$真是有病,petshop也要模仿,害我java的petshop有问题想用google搜一下都搜不到,全tm是.net的页面,faint

    [回复]

  9. hehe says:

    unrealwalker 真是搞笑。java版本的叫 petstore好不好?

    [回复]

  10. oldjacky says:

    # re: PetShop.NET有感 12/25/2004 1:41 AM unrealwalker
    M$真是有病,petshop也要模仿,害我java的petshop有问题想用google搜一下都搜不到,全tm是.net的页面,faint

    搞笑了撒~~

    [回复]

  11. kowloons says:

    开眼了!

    [回复]

  12. ter says:

    private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());

    private const string SQL_INSERT_ORDER = "Declare @ID int; Declare @ERR int; INSERT INTO Orders VALUES(@UserId, @Date, @ShipAddress1, @ShipAddress2, @ShipCity, @ShipState, @ShipZip, @ShipCountry, @BillAddress1, @BillAddress2, @BillCity, @BillState, @BillZip, @BillCountry, ‘UPS’, @Total, @BillFirstName, @BillLastName, @ShipFirstName, @ShipLastName, @CardNumber, @CardExpiration, @CardType, ‘US_en’); SELECT @ID=@@IDENTITY; INSERT INTO OrderStatus VALUES(@ID, @ID, GetDate(), ‘P’); SELECT @ERR=@@ERROR;";

    SqlParameter[] parms = GetCachedParameters(SQL_INSERT_ORDER);

    public static SqlParameter[] GetCachedParameters(string cacheKey) {
    SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];

    if (cachedParms == null)
    return null;

    SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];

    for (int i = 0, j = cachedParms.Length; i < j; i++)
    clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();

    return clonedParms;
    }

    其中的SqlParameter[] parms = GetCachedParameters(SQL_INSERT_ORDER);
    这样能把取到各参数吗?为什么呢,我看了很久都没明白。。

    [回复]

  13. ter says:

    private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());

    private const string SQL_INSERT_ORDER = "Declare @ID int; Declare @ERR int; INSERT INTO Orders VALUES(@UserId, @Date, @ShipAddress1, @ShipAddress2, @ShipCity, @ShipState, @ShipZip, @ShipCountry, @BillAddress1, @BillAddress2, @BillCity, @BillState, @BillZip, @BillCountry, ‘UPS’, @Total, @BillFirstName, @BillLastName, @ShipFirstName, @ShipLastName, @CardNumber, @CardExpiration, @CardType, ‘US_en’); SELECT @ID=@@IDENTITY; INSERT INTO OrderStatus VALUES(@ID, @ID, GetDate(), ‘P’); SELECT @ERR=@@ERROR;";

    SqlParameter[] parms = GetCachedParameters(SQL_INSERT_ORDER);

    public static SqlParameter[] GetCachedParameters(string cacheKey) {
    SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];

    if (cachedParms == null)
    return null;

    SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];

    for (int i = 0, j = cachedParms.Length; i < j; i++)
    clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();

    return clonedParms;
    }

    其中的SqlParameter[] parms = GetCachedParameters(SQL_INSERT_ORDER);
    这样能把取到各参数吗?为什么呢,我看了很久都没明白。。

    [回复]

  14. ter says:

    private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());

    private const string SQL_INSERT_ORDER = "Declare @ID int; Declare @ERR int; INSERT INTO Orders VALUES(@UserId, @Date, @ShipAddress1, @ShipAddress2, @ShipCity, @ShipState, @ShipZip, @ShipCountry, @BillAddress1, @BillAddress2, @BillCity, @BillState, @BillZip, @BillCountry, ‘UPS’, @Total, @BillFirstName, @BillLastName, @ShipFirstName, @ShipLastName, @CardNumber, @CardExpiration, @CardType, ‘US_en’); SELECT @ID=@@IDENTITY; INSERT INTO OrderStatus VALUES(@ID, @ID, GetDate(), ‘P’); SELECT @ERR=@@ERROR;";

    SqlParameter[] parms = GetCachedParameters(SQL_INSERT_ORDER);

    public static SqlParameter[] GetCachedParameters(string cacheKey) {
    SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];

    if (cachedParms == null)
    return null;

    SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];

    for (int i = 0, j = cachedParms.Length; i < j; i++)
    clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();

    return clonedParms;
    }

    其中的SqlParameter[] parms = GetCachedParameters(SQL_INSERT_ORDER);
    这样能把取到各参数吗?为什么呢,我看了很久都没明白。。

    [回复]

  15. killkill says:

    to ter

    你最好查找一次GetCachedParameters是在哪里引用的,你就知道了
    其实基本思想是用空间换时间,将Parameter[]存入哈希表里,下次调用的时候,就直接从哈希表里面取出来了,你要注意,这个哈希表可以声明为 static 的所以,随类的加载而被实例话,直到该类被销毁位置,所以,你要注意这个场景,线程A在执行某个方法的时候给哈希表里面存入了Paramter[] , 当线程B也执行的这个方法时,就从该哈希表里取出Paramter[]的Clone版本,这样就免去了创建对象的时间了,当这个Parameter[] 很大的时候,效果将会很明显,但是感觉Parameter也不是什么大对象,而且Parameter的维数应该不会太大。

    呵呵,欢迎大家指点。

    [回复]

  16. 即是空 says:

    其中的SqlParameter[] parms = GetCachedParameters(SQL_INSERT_ORDER);
    这样能把取到各参数吗?为什么呢,我看了很久都没明白。。

    如果看到我的留言的话请联系我一下好吗?谢谢

    QQ:455489926
    E-mail:
    Site: http://www.jskong.cn

    [回复]

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>