反射在.NET中的简单应用(二)

Attribute,特性(之所以不称作属性,是为了跟Property相区分),就是我们在程序中经常碰到的用[]括起来的那个东西,没错,他就是Attributes。

Attributes在.NET中的应用非常广泛,例如我们序列化的时候,需要用到Serializable,定义枚举的时候可能会用到FlagAttribute,定义自定义控件的时候用到的BrowsableAttribute等等,这些都是对Attribute的应用,有关Attribute的更多信息请参考MSDN(http://msdn.microsoft.com/en-us/library/system.attribute.aspx

在这篇文章中,我们用下面的例子来说明如何在.NET中应用自定义的Attribute

我们在做任何系统的时候,数据库中都会有些Master表,这些表的操作基本都比较简单,只是单表的增删改查

在这个例子中的做法,是给每个表都创建一个Entity的对象,表中的字段就是相应的Filed,然后给每个Entity以及Filed定义好相应的Attribute,这样就可以根据定义的属性自动生成SQL文以简化操作。

好了,下面就开始我们的准备工作。

首先我们需要建两个Attribute:

一个是定义表名的Attribute

  1. [AttributeUsage(AttributeTargets.Class)]
  2. internal class DBTableAttribute : Attribute
  3. {
  4.     private string tableName = String.Empty;
  5.     public DBTableAttribute(string tableName)
  6.     {
  7.         this.tableName = tableName;
  8.     }
  9.     public string TableName
  10.     {
  11.         get { return tableName; }
  12.         set { tableName = value; }
  13.     }
  14. }

这里需要注意一下AttributeTargets,它表示当前的Attribute的使用权限,有关AttributeTargets的更多信息,请参考MSDN(http://msdn.microsoft.com/zh-cn/library/system.attributetargets.aspx

还有一个定义字段的Attribute

  1. [AttributeUsage(AttributeTargets.Field)]
  2. internal class DBColumnAttribute : Attribute
  3. {
  4.     private string columnName;//对应数据库的字段名
  5.     private bool isPK;//是否主键
  6.     private bool isSequence;;//是否自增列
  7.     private bool isDelFlag;;//是否删除标记
  8.     public DBColumnAttribute(string columnName)
  9.             : this(columnName, falsefalsefalse)
  10.     {
  11.     }
  12.     public DBColumnAttribute(string columnName, bool isPK, bool isSequence, bool isDelFlag)
  13.     {
  14.         this.columnName = columnName;
  15.         this.isPK = isPK;
  16.         this.isSequence = isSequence;
  17.         this.isDelFlag = isDelFlag;
  18.     }
  19.     public string ColumnName
  20.     {
  21.         get { return columnName; }
  22.         set { columnName = value; }
  23.     }
  24.     public bool IsPK
  25.     {
  26.         get { return isPK; }
  27.         set { isPK = value; }
  28.     }
  29.     public bool IsSequence
  30.     {
  31.         get { return isSequence; }
  32.         set { isSequence = value; }
  33.     }
  34.     public bool IsDelFlag
  35.     {
  36.         get { return isDelFlag; }
  37.         set { isDelFlag = value; }
  38.     }
  39. }

这里的删除标记的意思是,在操作表的时候我们有时候并不是彻底删除数据,而是修改一个标志位来决定此条记录是否有效。

 

接下来我们定义两个辅助类,以便在程序中把Attribute的信息读到这两个类中

  1. internal class EntityAttributeInfo
  2. {
  3.     private string tableName = String.Empty;
  4.     private Dictionary<string, EntityColumnInfo> columnInfo = new Dictionary<string, EntityColumnInfo>();
  5.     public string TableName
  6.     {
  7.         get { return tableName; }
  8.         set { tableName = value; }
  9.     }
  10.     public Dictionary<string, EntityColumnInfo> ColumnInfo
  11.     {
  12.         get { return columnInfo; }
  13.         set { columnInfo = value; }
  14.     }
  15. }
  16. internal class EntityColumnInfo
  17. {
  18.     private string dbColumnName = String.Empty;
  19.     private string dalColumnName = String.Empty;//数据库的字段对应程序中的Filed的名称,以便使用反射来赋值
  20.     private bool isPK;
  21.     private bool isSequence;
  22.     private bool isDelFlag;
  23.     public string DbColumnName
  24.     {
  25.         get { return dbColumnName; }
  26.         set { dbColumnName = value; }
  27.     }
  28.     public string DALColumnName
  29.     {
  30.         get { return dalColumnName; }
  31.         set { dalColumnName = value; }
  32.     }
  33.     public bool IsPK
  34.     {
  35.         get { return isPK; }
  36.         set { isPK = value; }
  37.     }
  38.     public bool IsSequence
  39.     {
  40.         get { return isSequence; }
  41.         set { isSequence = value; }
  42.     }
  43.     public bool IsDelFlag
  44.     {
  45.         get { return isDelFlag; }
  46.         set { isDelFlag = value; }
  47.     }
  48. }

然后我们建一个接口,供其他的Entity来继承

  1. //目前只是空的接口,如果有需要可以增加自己的业务逻辑
  2. public interface IEntity
  3. {
  4. }

好了,准备工作已经完毕,现在来看看我们的表吧

假设我们有表名为tbTest,有如下字段

ColumnName    ColumnType    IsPK    IsSequence    IsNullable

Column1           int                     true       true               false

Column2           string                false      false               false

Column3           string                false       false              true

Column4           int                    false       false               false

 

那么我们的Entity应该有如下定义

  1. [DBTableAttribute("tbTest")]
  2. public class TestEntity : IEntity
  3. {
  4.     [DBColumn("Column1", IsPK = true, IsSequence = true, IsDelFlag = false)]
  5.     private int column1;
  6.     public int Column1
  7.     {
  8.         get { return column1; }
  9.         set { column1 = value; }
  10.     }
  11.     [DBColumn("Column2", IsPK = false, IsSequence = false, IsDelFlag = false)]
  12.     private string column2;
  13.     public string Column2
  14.     {
  15.         get { return column2; }
  16.         set { column2 = value; }
  17.     }
  18.     [DBColumn("Column3", IsPK = false, IsSequence = false, IsDelFlag = false)]
  19.     private string? column3;
  20.     public string? Column3
  21.     {
  22.         get { return column3; }
  23.         set { column3 = value; }
  24.     }
  25.     [DBColumn("Column4", IsPK = true, IsSequence = false, IsDelFlag = true)]
  26.     private int column4;
  27.     public int Column4
  28.     {
  29.         get { return column4; }
  30.         set { column4 = value; }
  31.     }
  32. }

然后我们建一个AttributeReader来读取自定义的Attribute的信息

  1. internal class AttributeReader
  2. {
  3.     public static EntityAttributeInfo GetAttributeInfo(IEntity etity)
  4.     {
  5.         Type type = etity.GetType();
  6.         return GetAttributeInfo(type);
  7.     }
  8.     public static EntityAttributeInfo GetAttributeInfo(Type type)
  9.     {
  10.         EntityAttributeInfo info = new EntityAttributeInfo();
  11.         info.TableName = GetTableName(type);
  12.         foreach (FieldInfo field in
  13.                 type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
  14.         {
  15.             EntityColumnInfo item = GetColumnInfo(field);
  16.             if (item != null)
  17.             {
  18.                 info.ColumnInfo.Add(item.DbColumnName, item);
  19.             }
  20.         }
  21.         return info;
  22.     }
  23.     public static string GetTableName(Type type)
  24.     {
  25.         object[] oo = type.GetCustomAttributes(typeof(DBTableAttribute), false);
  26.         if (oo.Length > 0)
  27.         {
  28.             return (oo[0] as DBTableAttribute).TableName;
  29.         }
  30.         return null;
  31.     }
  32.     private static EntityColumnInfo GetColumnInfo(FieldInfo field)
  33.     {
  34.         EntityColumnInfo info = null;
  35.         object[] oo = field.GetCustomAttributes(typeof(DBColumnAttribute), false);
  36.         if (oo.Length > 0)
  37.         {
  38.             DBColumnAttribute columnAttr = oo[0] as DBColumnAttribute;
  39.             info = new EntityColumnInfo();
  40.             info.DbColumnName = columnAttr.ColumnName;
  41.             info.DALColumnName = field.Name;
  42.             info.IsPK = columnAttr.IsPK;
  43.             info.IsSequence = columnAttr.IsSequence;
  44.             info.IsDelFlag = columnAttr.IsDelFlag;
  45.         }
  46.         return info;
  47.     }
  48. }

最后我们创建一个EntityManager来实现最终的增删改查的SQL文

  1. public class EntityManager
  2. {
  3.     public void Insert(IEntity entity)
  4.     {
  5.         try
  6.         {
  7.             EntityAttributeInfo attInfo = AttributeReader.GetAttributeInfo(entity);
  8.             if (String.IsNullOrEmpty(attInfo.TableName))
  9.             {
  10.                 throw new Exception(entity.GetType().Name + " cannot be insert to DB,because tablename is null.");
  11.             }
  12.             StringBuilder sb = new StringBuilder();
  13.             StringBuilder sbColumn = new StringBuilder();
  14.             StringBuilder sbValue = new StringBuilder();
  15.             List<SqlParameter> parameters = new List<SqlParameter>();
  16.             Dictionary<string, EntityColumnInfo> columnInfos = attInfo.ColumnInfo;
  17.             string sequenceField = String.Empty;
  18.             foreach (EntityColumnInfo item in columnInfos.Values)
  19.             {
  20.                 if (item.IsDelFlag)
  21.                 {
  22.                     SetObjectMemberValue(entity, item.DALColumnName, "1");
  23.                 }
  24.                 if (!item.IsSequence)
  25.                 {
  26.                     sbColumn.AppendFormat("{0},", item.DbColumnName);
  27.                     string parameterName = "@" + item.DbColumnName;
  28.                     sbValue.AppendFormat("{0},", parameterName);
  29.                     object parameterValue = GetObjectMemberValue(entity, item.DALColumnName);
  30.                     parameters.Add(new SqlParameter(parameterName, GetDBValue(parameterValue)));                  
  31.                 }
  32.                 else
  33.                 {
  34.                     sequenceField = item.DALColumnName;
  35.                 }
  36.             }
  37.             sb.AppendFormat("INSERT INTO {0} ", attInfo.TableName);
  38.             sb.Append("(");
  39.             sb.Append(sbColumn.ToString().TrimEnd(','));
  40.             sb.Append(")");
  41.             sb.Append(" VALUES ");
  42.             sb.Append("(");
  43.             sb.Append(sbValue.ToString().TrimEnd(','));
  44.             sb.Append(")");
  45.             if (!String.IsNullOrEmpty(sequenceField))
  46.             {
  47.                 sb.Append(";SELECT @@identity");
  48.                 object sequenceValue = DBService.Instance.ExecuteScalar(sb.ToString(), parameters);
  49.                 SetObjectMemberValue(entity, sequenceField, Convert.ToInt32(sequenceValue));
  50.             }
  51.             else
  52.             {
  53.                 DBService.Instance.ExecuteNonQuery(sb.ToString(), parameters);
  54.             }
  55.         }
  56.         catch (Exception ex)
  57.         {
  58.             throw ex;
  59.         }
  60.     }
  61.     public void Update(IEntity entity)
  62.     {
  63.         try
  64.         {
  65.             EntityAttributeInfo attInfo = AttributeReader.GetAttributeInfo(entity);
  66.             if (String.IsNullOrEmpty(attInfo.TableName))
  67.             {
  68.                 throw new Exception(entity.GetType().Name + " cannot be update to DB,because tablename is null.");
  69.             }
  70.             StringBuilder sbUpdate = new StringBuilder();
  71.             StringBuilder sbWhere = new StringBuilder();
  72.             List<SqlParameter> parameters = new List<SqlParameter>();
  73.             Dictionary<string, EntityColumnInfo> columnInfos = attInfo.ColumnInfo;
  74.             foreach (EntityColumnInfo item in columnInfos.Values)
  75.             {
  76.                 if (item.IsPK)
  77.                 {
  78.                     object parameterValue = GetObjectMemberValue(entity, item.DALColumnName);
  79.                     string parameterName = "@" + item.DbColumnName;
  80.                     parameters.Add(new SqlParameter(parameterName, GetDBValue(parameterValue)));
  81.                     sbWhere.AppendFormat("AND {0} = @{0} ", item.DbColumnName);
  82.                 }
  83.                 else
  84.                 {
  85.                     sbUpdate.AppendFormat("{0} = @{0},", item.DbColumnName);
  86.                 }
  87.             }
  88.             string sql = String.Format("UPDATE {0} SET {1} WHERE 1=1 {2}",
  89.                     attInfo.TableName, sbUpdate.ToString().TrimEnd(','), sbWhere.ToString());
  90.             DBService.Instance.ExecuteNonQuery(sql, parameters);
  91.         }
  92.         catch (Exception ex)
  93.         {
  94.             throw ex;
  95.         }
  96.     }
  97.     public void Delete(IEntity entity)
  98.     {
  99.         try
  100.         {
  101.             EntityAttributeInfo attInfo = AttributeReader.GetAttributeInfo(entity);
  102.             if (String.IsNullOrEmpty(attInfo.TableName))
  103.             {
  104.                 throw new Exception(entity.GetType().Name + " cannot be delete to DB,because tablename is null.");
  105.             }
  106.             string sql = String.Empty;
  107.             StringBuilder sbWhere = new StringBuilder();
  108.             List<SqlParameter> parameters = new List<SqlParameter>();
  109.             Dictionary<string, EntityColumnInfo> columnInfos = attInfo.ColumnInfo;
  110.             string delFlagColumn = String.Empty;
  111.             foreach (EntityColumnInfo item in columnInfos.Values)
  112.             {
  113.                 if (item.IsDelFlag)
  114.                 {
  115.                     delFlagColumn = item.DbColumnName;
  116.                 }
  117.                 if (item.IsPK)
  118.                 {
  119.                     object parameterValue = GetObjectMemberValue(entity, item.DALColumnName);
  120.                     string parameterName = "@" + item.DbColumnName;
  121.                     parameters.Add(new SqlParameter(parameterName, GetDBValue(parameterValue)));
  122.                     sbWhere.AppendFormat("AND {0} = @{0} ", item.DbColumnName);
  123.                 }
  124.             }
  125.             if (String.IsNullOrEmpty(delFlagColumn))
  126.             {
  127.                 sql = String.Format("DELETE FROM {0} WHERE 1=1 {1}", attInfo.TableName, sbWhere.ToString());
  128.             }
  129.             else
  130.             {
  131.                 sql = String.Format("UPDATE {0} SET {1} = 0 WHERE 1=1 {2} "
  132.                         attInfo.TableName, delFlagColumn, sbWhere.ToString());
  133.             }
  134.             DBService.Instance.ExecuteNonQuery(sql, parameters);
  135.         }
  136.         catch (Exception ex)
  137.         {
  138.             throw ex;
  139.         }
  140.     }
  141.     public List<IEntity> GetEntities(Type type)
  142.     {
  143.         return GetEntities(type, nullnull);
  144.     }
  145.     public List<IEntity> GetEntities(Type type, string where, List<SqlParameter> parameters)
  146.     {
  147.         List<IEntity> entities = new List<IEntity>();
  148.         StringBuilder sb = new StringBuilder();
  149.         string tableName = AttributeReader.GetTableName(type);
  150.         if (!String.IsNullOrEmpty(tableName))
  151.         {
  152.             sb.AppendFormat("SELECT * FROM {0} ", tableName);
  153.             if (!String.IsNullOrEmpty(where) && parameters != null && parameters.Count > 0)
  154.             {
  155.                 sb.AppendFormat("WHERE {0}", where);
  156.             }
  157.             DataTable table = DBService.Instance.ExecuteDataTable(sb.ToString(), tableName, parameters);
  158.             if (table != null)
  159.             {
  160.                 foreach (DataRow row in table.Rows)
  161.                 {
  162.                     IEntity entity = RowMapping2Entity(type, row);
  163.                     entities.Add(entity);
  164.                 }
  165.             }
  166.         }
  167.         return entities;
  168.     }
  169.     public IEntity GetEntity(Type type, string where, List<SqlParameter> parameters)
  170.     {
  171.         StringBuilder sb = new StringBuilder();
  172.         string tableName = AttributeReader.GetTableName(type);
  173.         IEntity entity = null;
  174.         if (!String.IsNullOrEmpty(tableName))
  175.         {
  176.             sb.AppendFormat("SELECT TOP 1 * FROM {0} ", tableName);
  177.             if (!String.IsNullOrEmpty(where))
  178.             {
  179.                 sb.AppendFormat("WHERE {0}", where);
  180.             }
  181.             DataTable table = DBService.Instance.ExecuteDataTable(sb.ToString(), tableName, parameters);
  182.             if (table != null && table.Rows.Count > 0)
  183.             {
  184.                 entity = RowMapping2Entity(type, table.Rows[0]);
  185.             }
  186.         }
  187.         return entity;
  188.     }
  189.     private object GetObjectMemberValue(IEntity entity ,string memberName)
  190.     {
  191.         FieldInfo field = GetField(entity, memberName);
  192.         return field.GetValue(entity);
  193.     }
  194.     private void SetObjectMemberValue(IEntity entity, string memberName, object memberValue)
  195.     {
  196.         FieldInfo field = GetField(entity, memberName);
  197.         field.SetValue(entity, GetObjValue(memberValue));
  198.     }
  199.     private FieldInfo GetField(IEntity entity, string memberName)
  200.     {
  201.         return entity.GetType().GetField(memberName, BindingFlags.Instance | BindingFlags.NonPublic);
  202.     }
  203.     private object GetDBValue(object obj)
  204.     {
  205.         if (obj == null)
  206.         {
  207.             return DBNull.Value;
  208.         }
  209.         return obj;
  210.     }
  211.     private object GetObjValue(object obj)
  212.     {
  213.         if (obj == DBNull.Value)
  214.         {
  215.             return null;
  216.         }
  217.         return obj;
  218.     }
  219.     private IEntity RowMapping2Entity(Type type, DataRow row)
  220.     {
  221.         IEntity entity = Activator.CreateInstance(type) as IEntity;
  222.         EntityAttributeInfo attInfo = AttributeReader.GetAttributeInfo(entity);
  223.         foreach (EntityColumnInfo columninfo in attInfo.ColumnInfo.Values)
  224.         {
  225.             SetObjectMemberValue(entity, columninfo.DALColumnName, row[columninfo.DbColumnName]);
  226.         }
  227.         return entity;
  228.     }
  229. }

这里的DBService替换成你的方法就可以了

好了,这个例子到这里就结束了

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值