代码改变世界

数据访问帮助类-Unity简单实现

2011-10-30 22:02  Chanx  阅读(904)  评论(1编辑  收藏  举报

Unity是微软patterns & practices组用C#实现的轻量级,可扩展的依赖注入容器,它为方便开发者建立松散耦合的应用程序,有以下优点:

  简化了对象的创建,特别是针对分层对象结构和依赖关系;

  需求的抽象,允许开发人员在运行时或配置文件中指定依赖关系,简化横切关注点的管理;

  推迟为容器配置组件的时机,增加了灵活性;

  服务定位能力,这使客户能够存储或缓存容器;

  实例和类型拦截

下载地址:http://unity.codeplex.com/

出于对蒋金楠老师《WCF技术剖析》的阅读,接触了Unity,然而该书最后的PetShop讲大部分的重点放在了WCF与Unity结合上,那么在平常的应用开发中,怎样简单的结合Unity容器实现注入呢...

 

1、出于练习的目的,通过ADO.NET技术在数据访问上写了一个连接方式进行数据访问

 1 public class DBhelper
2 {
3 private DbProviderFactory _dbProviderFactory; //配置文件中的数据源类型
4 private string _connectionString; //连接字符串
5 private DbConnection CreateConnection() //建立数据库连接
6 {
7 DbConnection connection = this._dbProviderFactory.CreateConnection();
8 connection.ConnectionString = this._connectionString;
9 return connection;
10 }
11
12 public DBhelper(string connectionStringName) //构造函数,初始化时获取配置文件配置参数
13 {
14 string providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
15 this._connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
16 this._dbProviderFactory = DbProviderFactories.GetFactory(providerName);
17 }
18
19 //返回单个值(影响的行数、COUNT、MAX、MIN等等)
20 public int SqlScalar(string sqlstr)
21 {
22 DbConnection conn = this.CreateConnection();
23 conn.Open();
24 DbCommand command = conn.CreateCommand();
25 command.CommandType = CommandType.Text;
26 command.CommandText = sqlstr;
27 int num = (int)command.ExecuteScalar();
28 conn.Close();
29 return num;
30 }
31
32 //返回数据行的集合
33 public DbDataReader ExecuteReader(string sqlstr)
34 {
35 DbConnection conn = this.CreateConnection();
36 conn.Open();
37 using (DbCommand command = conn.CreateCommand())
38 {
39 command.CommandType = CommandType.Text;
40 command.CommandText = sqlstr;
41 return command.ExecuteReader(CommandBehavior.CloseConnection);
42 }
43 }
44
45 //用于更新、改变数据库
46 public bool ExecuteNonQuery(string sqlstr)
47 {
48 DbConnection conn = this.CreateConnection();
49 conn.Open(); //打开连接
50 DbTransaction tran = conn.BeginTransaction(); //开启事务
51 using (DbCommand command = conn.CreateCommand())
52 {
53 command.Transaction = tran; //command命令加入到事务中
54 command.CommandType = CommandType.Text;
55 command.CommandText = sqlstr;
56 command.ExecuteNonQuery();
57 try
58 {
59 tran.Commit(); //事务确认
60 conn.Close();
61 return true;
62 }
63 catch (System.Exception)
64 {
65 tran.Rollback(); //事务回滚
66 conn.Close();
67 return false;
68 }
69 }
70
71 }
72 }

注解:主要是通过Command对象的三个方法进行数据操作ExecuteReader、ExecuteScalar、ExecuteNonQuery

        其中在数据更新、插入等操作上开启了事务,防止数据在运行时发生错误影响数据库数据。

        当然,这里只是简单的实现数据的查询、更新等操作,至于非连接方式的数据访问,比如数据集DataSet,这里不涉及应用。


2、涉及数据库访问对象的生成,我们知道,在调用这个对象的时候,经常每调用一次实例化一个对象,造成了内存的浪费以及性能的影响,一个比较好的办法就是,让类自身负责保护它的唯一的实例,并且它可以提供一个访问该实例的方法,这里涉及到了Singleton-单例模式

     在这里,我定义了一个DataBase类,通过静态初始化的方式创建实例,并且防止多个对象的生成:

 1 public class DataAccessBase
2 {
3 //单例模式 静态初始化
4 private static readonly DBhelper helper = new DBhelper("UnityDemo");
5
6 protected DBhelper Helper
7 {
8 get
9 {
10 return helper;
11 }
12 }
13 }

 

3、在数据访问层UserDA,简单的定义一个GetAllUsers方法,通过DataReader对象访问数据库的字段的值赋值给业务实体...

 1 public User[] GetAllUsers()
2 {
3 List<User> users = new List<User>();
4 using (DbDataReader reader = this.Helper.ExecuteReader("select * from Users"))
5 {
6 while (reader.Read())
7 {
8 users.Add(new User
9 {
10 UId = (int)reader["UId"],
11 UserName = (string)reader["UserName"],
12 UserPassword = (string)reader["UserPassword"],
13 UserSex = (string)reader["UserSex"],
14 UserAge = (int)reader["UserAge"],
15 UserCity = (string)reader["UserCity"]
16 });
17 }
18 }
19 return users.ToArray<User>();
20 }


4、业务逻辑层UserBC,继承一个接口IUser,并通过属性注入(Property Injectin)方式对UserDA添加依赖

    添加Microsoft.Practices.Unity;命名空间,在依赖属性上标注一个自定义特性Dependency,在UserBC对象被成功创建之后,Unity会立即为这些属性进行初始化。代码如下:

1 [Dependency]
2 public UserDA DataAccess { get; set; }
3
4 //UserDA DataAccess = new UserDA();
5
6 public User[] GetAllUsers()
7 {
8 return this.DataAccess.GetAllUsers();
9 }

 

5、在生成UserBC对象的之前,,需要实例化一个UnityContainer容器,通过Container容器的Resolve方法建立该类一个对象,同时,在该对象被创建的同时,标注了Dependency特性的属性会自动进行初始化,考虑到经常调用Container容器的对象,这里我们通过泛型建立一个帮助类

1 public static class UnityBase
2 {
3 public static T Container<T>()
4 {
5 IUnityContainer con = new UnityContainer();
6 T unity = con.Resolve<T>();
7 return unity;
8 }
9 }

 

6、那么我们访问GetAllUser方法的时候,只需要通过以下方式实现

1 IUser bc = UnityBase.Container<UserBC>();
2
3 public void ListAllUser()
4 {
5 this.View.BindAllUsers(bc.GetAllUsers());
6 }

  最后通过ASP.NET中的DataList控件即可绑定数据......

  实例下载

疑虑:本人对Unity只是粗浅的了解,对.NET的各种可以实现注入技术的框架是充满兴趣却又无从下手,希望各位大虾可以提点一二,在学校接触不了企业级项目开发,对各层级的解耦,以及横切点(AOP)等技术实现充满疑虑。

     在本例中,上述的泛型帮助类中,对UnityContainer对象的生成产生了疑虑,暂时没有想到方法解决。

     就是,当B类和C类同时依赖于A类时,我们各自在B、C类添加对A类的属性注入,当我们调用B、C类方法的时候,即实现B、C的同时对A类型的属性进行了初始化,那么,因为通过Dependency标注属性,对A的初始化就产生了两次,那么Unity内部是否会对A的对象产生次数进行优化呢,我们能怎么做呢?
     

总结:本例有很多不完善的地方,主要是使用一个方法,通过Unity的容器实现依赖注入...希望大家可以交流交流...