博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

浅写数据库反射类--泛型dao

Posted on 2009-12-11 21:12  SkyPurple  阅读(721)  评论(0)    收藏  举报

   随着.net Framework版本的升级

 1.0--托管代码

 2.0--泛型,匿名方法

   3.0--linq,lambda表达式

   给软件开发界带来了激动人心的特性,但是也给程序员带来了新的挑战。

 

 今天发一个2.0泛型dao(当然在3.0语法中,用linq,或者lambda表达式能轻松写出来)

 思路,利用reflection得到class的相关信息

 不废话。。。。

 首先考虑自定义特性(一为描述表,二为描述列)--描述表名类:class TableAttribute

代码
 1     /// <summary>
 2     /// 描述表
 3     /// </summary>
 4     [AttributeUsage(AttributeTargets.Class)]
 5     public class TableAttribute : Attribute
 6     {
 7         public TableAttribute(string tableName)
 8         {
 9             this._tableName = tableName;
10         }
11         private string _tableName;
12 
13         public string TableName
14         {
15             get { return _tableName; }
16             set { _tableName = value; }
17         }
18     }

 

   在描述表名类中,此类为一个自定义特性,内容为表名,需继承Attribute 并且写入特性为描述类

 

   其次为--描述属性类:class ColumnAttribute

代码
    /// <summary>
    
/// 描述列
    
/// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    
public class ColumnAttribute : Attribute
    {
        
public ColumnAttribute(string columnName,bool isIdentity,bool isPrimaryKey)
        {
            
this._columnName = columnName;
            
this._isIdentity = isIdentity;
            
this._isPrimaryKey = isPrimaryKey;
        }
        
private string _columnName;

        
public string ColumnName
        {
            
get { return _columnName; }
            
set { _columnName = value; }
        }
        
private bool _isIdentity;

        
public bool IsIdentity
        {
            
get { return _isIdentity; }
            
set { _isIdentity = value; }
        }
        
private bool _isPrimaryKey;

        
public bool IsPrimaryKey
        {
            
get { return _isPrimaryKey; }
            
set { _isPrimaryKey = value; }
        }
    }

 

 在描述属性中除了AttributeTargets是描述属性的特性外,其余相同,其中列名,是否为主键,是否为自增列

 

我们假设现在有数据库有一张表名为Customers

那么Models层中的Customer类的写法为(一般表名为英文复数而实体名为单数,加S与不加S的区别):

Customer类:

代码
  [TableAttribute("Customers")]
    
public class Customer
    {
        
        
private string _customerID;
        [ColumnAttribute(
"CustomerID"falsetrue)]
        
public string CustomerID
        {
            
get { return _customerID; }
            
set { _customerID = value; }
        }
        
        
private string _customerName;
        [ColumnAttribute(
"CustomerName"falsefalse)]
        
public string CustomerName
        {
            
get { return _customerName; }
            
set { _customerName = value; }
        }
        
        
private DateTime _birthday;
        [ColumnAttribute(
"Birthday"falsefalse)]
        
public DateTime Birthday
        {
            
get { return _birthday; }
            
set { _birthday = value; }
        }
    }

 

  在类上用我们自定义的特性(描述表的特性--C#代码智能感应可能感应不出完全的特性名称所以各位在写代码时不用在意)写出表名,我们知道,每一个数据库表中的每一个字段对应我们类中的每一个属性,所以在每一个属性上写出自定义描述列的特性,名称为数据库的对应的字段名称。

 

 到这里我们对数据库表的描述已经结束,现在我们来看看 利用反射与泛型对数据库的操作:

 

Entity类:

 

 

代码
代码
    
public class Entity
    {
        
private string _connString = string.Empty;
        
public Entity(string connString)
        {
            
this._connString = connString;
        }
        
/// <summary>
        
/// 查询
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <returns></returns>
        public List<T> ToList<T>() where T : class , new()
        {
            List
<T> tList = new List<T>();
            Type type 
= typeof(T);
            
string sql = string.Format("select * from {0}", GetTableName<T>());
            
using (SqlConnection conn = new SqlConnection(_connString))
            {
                SqlCommand command 
= new SqlCommand(sql, conn);
                conn.Open();
                SqlDataReader reader 
= command.ExecuteReader();
                
while(reader.Read())
                {
                    T t 
= new T();
                    PropertyInfo[] properties 
= type.GetProperties();
                    
foreach (PropertyInfo p in properties)
                    {
                        
string columnName = GetColumnName(p);
                        p.SetValue(t, reader[columnName], 
null);
                    }
                    tList.Add(t);
                }
                reader.Close();
            }
            
return tList;
        }
        
/// <summary>
        
/// 获取表名
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <returns></returns>
        private string GetTableName<T>()
        {
            
string tableName = string.Empty;
            Type type 
= typeof(T);
            Object[] objs 
= type.GetCustomAttributes(typeof(TableAttribute), true);
            
if (objs.Length > 0)
            {
                TableAttribute tAttribute 
= objs[0as TableAttribute;
                tableName 
= tAttribute.TableName;
            }
            
return tableName;
        }

        
/// <summary>
        
/// 获取列名
        
/// </summary>
        
/// <param name="proper"></param>
        
/// <returns></returns>
        private string GetColumnName(PropertyInfo proper)
        {
            
string columnName = string.Empty;
            Object[] objs 
= proper.GetCustomAttributes(typeof(ColumnAttribute),true);
            
if (objs.Length > 0)
            {
                ColumnAttribute cAttribute 
= objs[0as ColumnAttribute;
                columnName 
= cAttribute.ColumnName;
            }
            
return columnName;
        }


   }

 

这里我使用了sqlserver数据库来简写,当然大家也可以写一个DBHelper 然后DbProviderFactories动态的决定使用哪一种数据库

也是抽象工厂吧!继续解释上面的代码:我只写了一种一查询数据库该表的所有数据,当然,查询哪一张表 由传入的类型决定,

这里的where T : class , new() 表示泛型约束,约束传入的类型为class,并且具有空构造

ok---

测试为:

代码
    class Program
    {
        
static void Main(string[] args)
        {
            Entity en 
= new Entity(@"Data Source=.\sql2k5;Initial Catalog=TBD;Integrated Security=True");
            List
<Customer> cuList = en.ToList<Customer>();
            
foreach (Customer cu in cuList)
            {
                Console.WriteLine(cu.CustomerID 
+ cu.CustomerName + cu.Birthday.ToShortDateString());
            }
         }
     }

 

在测试中,我传入了连接字符串(为测试,正式项目请各位不要学我这样写)

大家可以看见,在测试中,我只需要Entity类的ToList方法就能得到该实体类在数据库中的所有数据

 

OK。到这里结束,再声明一次,代码也许有许多不规范的地方请学习的同志注意,并且在Entity类中的连接数据库各位可以再抽象再封装

 

写的不好,请不要拍板砖