最近整理以前的資料,想起來了這個小東西,以前感覺反射效率應該不行,後來翻看了nhibernate的源代碼徹底改變了我的觀點,隨後自己動手寫了這個小東西玩玩,大牛就不用看了,對反射有意思的可以瞧瞧
基本原理說明,我將業務類用自定義屬性[CustAttribute]進行標註,然後用ado.net 獲取數據集,將數據集中列名與對應業務類屬性名稱相同的進行填充操作,思路簡單明瞭。
自定義CustAttribute類:
/// <summary>
/// 自定義屬性類,用於識別要映射的屬性
/// </summary>
//[AttributeUsage(Inherited = true,AllowMultiple =true)]
public class CustAttribute:Attribute
{
}
結果集映射類:
/// <summary>
/// 將DataTable映射到class
/// </summary>
/// <typeparam name="T"></typeparam>
public class DataRowClassMap<T> where T: class
{
/// <summary>
/// 將DataRow中的數據映射到item中
/// </summary>
/// <param name="dr"></param>
/// <param name="item"></param>
/// <returns></returns>
public static T GetData(DataRow dr, T item)
{
if (item ==null||dr == null || dr.Table.Columns.Count == 0)
return null;
//獲取類的公共屬性
List<PropertyInfo> SelfPropertyList = GetSelfProperties(typeof(T));
//循環獲得各個屬性
foreach (PropertyInfo info in SelfPropertyList)
{
//判斷當前DataRow中是否含有當前屬性
if (dr.Table.Columns.Contains(info.Name) == false)
{
LibraryException.WriteErrorLoc(string.Format("沒有找到類{0}的{1}屬性", typeof(T).ToString(),info.Name));
return null;
}
if (dr[info.Name] == DBNull.Value)
{
//如果是可空類型則直接賦值爲null
if (info.GetValue(item, null) == null)
{
continue;
}
//不是空類型也直接返回
continue;
}
//根據屬性類型獲取對應的轉換值
object value = GetTypeValue(info, dr[info.Name]);
if (value == null)
{
LibraryException.WriteErrorLoc(string.Format("數據轉換失敗!類{0}的{1}屬性嘗試將值{3}轉換失敗", typeof(T).ToString(), info.Name,dr[info.Name]));
return null;
}
info.SetValue(item, value, null);
}
return item;
}
/// <summary>
/// 獲得當前類中自定義屬性,不包含繼承的
/// </summary>
/// <param name="type"></param>
private static List<PropertyInfo> GetSelfProperties(Type type)
{
List<PropertyInfo> SelfPropertyList = null;
try
{
//獲取對象的共有屬性,並且是標誌了自定義特性的屬性。
SelfPropertyList = type.GetProperties(BindingFlags.Public
| BindingFlags.Instance | BindingFlags.DeclaredOnly)
.ToList().FindAll(x => x.MemberType == MemberTypes.Property&&x.GetCustomAttributes(typeof(CustAttribute),false).Count()>0);
}
catch (Exception ex)
{
LibraryException.WriteErrorLoc(ex.Message);
}
return SelfPropertyList;
}
/// <summary>
/// 根據類型獲取對應的類型值
/// </summary>
/// <param name="info"></param>
/// <param name="p"></param>
/// <returns></returns>
private static object GetTypeValue(PropertyInfo info, object p)
{
try
{
Type type = info.PropertyType;
//判斷是否是Nullable<>類型
if (type.IsGenericType == true && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
//獲取基類型
type = type.GetGenericArguments()[0];
}
//如果等於string類型
if (type.Equals(typeof(string)))
return p;
if (type.Equals(typeof(Guid)))
return new Guid(p.ToString());
if (type.Equals(typeof(DateTime)))
return DateTime.Parse(p.ToString());
MethodInfo methord = type.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] {typeof(string)},null);
if (methord == null)
{
LibraryException.WriteErrorLoc(string.Format("數據轉換失敗!類{0}的{1}屬性沒有Parse(string)方法", info.DeclaringType.Name, info.Name));
return null;
}
var value = methord.Invoke(null, new object[] { p.ToString() });
return value;
}
catch (Exception ex)
{
LibraryException.WriteErrorLoc(string.Format("數據轉換失敗!類{0}的{1}屬性嘗試將值{3}轉換失敗,失敗原因{4}", info.DeclaringType.Name, info.Name,p.ToString(),ex.Message));
return null;
}
}
}
使用示例:
有如下Order業務類定義
public class SaleOrder
{
#region 屬性
[<span style="font-family: Arial, Helvetica, sans-serif;">CustAttribute</span><span style="font-family: Arial, Helvetica, sans-serif;">]</span>
public Guid ID { get; set; }
/// <summary>
/// 主鍵ID
/// </summary>
<pre name="code" class="csharp"> [<span style="font-family: Arial, Helvetica, sans-serif;">CustAttribute</span><span style="font-family: Arial, Helvetica, sans-serif;">]</span>
public string OrderName {get;set;}
<pre name="code" class="csharp"> [<span style="font-family: Arial, Helvetica, sans-serif;">CustAttribute</span><span style="font-family: Arial, Helvetica, sans-serif;">]</span>
<span style="font-family: Arial, Helvetica, sans-serif;"> public decimal Amount {get;set;}</span>
<span style="font-family: Arial, Helvetica, sans-serif;"> ........................</span>
需求是根據ID獲取單個SaleOrder數據
/// <summary>
///根據ID獲取SaleOrder對象
/// </summary>
/// <param name="ID"></param>
public static SaleOrder GetDataByID(Guid ID)
{
try
{
string sqlstr = string.Format("select top 1 * from Inv_SaleOrder where ID='{0} '",ID.ToString());
DataTable table = DataAccess.GetDataTable(sqlstr);
if (table == null || table.Rows.Count == 0)
return null;
SaleOrder order = new SaleOrder();
DataRow dr = table.Rows[0]; //獲得一行數據
DataRowClassMap<SaleOrder>.GetData(dr, order);//填充對象
}
catch (Exception ex)
{
throw ex;
}
}
如果沒有DataRowClassMap 進行填充數據,那我就得用如下的方法敲代碼,一個類還行,要是多了手酸眼花
<pre name="code" class="csharp"> #region 老代碼
//private void GateData(DataRow dr)
//{
// this.TaxStkAmount = decimal.Parse(dr["TaxStkAmount"].ToString().Trim());
// this.LocTaxStkAmount = decimal.Parse(dr["LocTaxStkAmount"].ToString().Trim());
// this.StkAmountTax = decimal.Parse(dr["StkAmountTax"].ToString().Trim());
// this.LocStkAmountTax = decimal.Parse(dr["LocStkAmountTax"].ToString().Trim());
// this.TaxSrvAmount = decimal.Parse(dr["TaxSrvAmount"].ToString().Trim());
// this.LocTaxSrvAmount = decimal.Parse(dr["LocTaxSrvAmount"].ToString().Trim());
// this.LocSrvAmountTax = decimal.Parse(dr["LocSrvAmountTax"].ToString().Trim());
// this.TaxAmount = decimal.Parse(dr["TaxAmount"].ToString().Trim());
// this.TaxAllowance = decimal.Parse(dr["TaxAllowance"].ToString().Trim());
// this.LocTaxAllowance = decimal.Parse(dr["LocTaxAllowance"].ToString().Trim());
// this.AmountTax = decimal.Parse(dr["AmountTax"].ToString().Trim());
// this.LocAmountTax = decimal.Parse(dr["LocAmountTax"].ToString().Trim());
// this.LocTaxTrnAmount = decimal.Parse(dr["LocTaxTrnAmount"].ToString().Trim());
// this.TaxTrnAmount = decimal.Parse(dr["TaxTrnAmount"].ToString().Trim());
// this.Payment_ID = int.Parse(dr["Payment_ID"].ToString().Trim());
// this.MnyNo = dr["MnyNo"].ToString().Trim();
// this.ExRate = decimal.Parse(dr["ExRate"].ToString().Trim());
// this.DocNumber = dr["DocNumber"].ToString().Trim();
// this.TrnDate = DateTime.Parse(dr["TrnDate"].ToString().Trim());
// this.AcntPeriod = dr["AcntPeriod"].ToString().Trim();
// this.PostDate = DateTime.Parse(dr["PostDate"].ToString().Trim());
// this.DocFlag = int.Parse(dr["DocFlag"].ToString().Trim());
// this.SendDate = DateTime.Parse(dr["SendDate"].ToString().Trim());
// this.UpdatedBy = dr["UpdatedBy"] == DBNull.Value ? new Nullable<Guid>() : new Guid(dr["UpdatedBy"].ToString().Trim());
// this.UpdateTime = dr["UpdateTime"] == DBNull.Value ? new Nullable<DateTime>() : DateTime.Parse(dr["UpdateTime"].ToString().Trim());
// this.Description = dr["Description"].ToString().Trim();
// this.ProjectID = new Guid(dr["ProjectID"].ToString().Trim());
// this.SaleManID = new Guid(dr["SaleManID"].ToString().Trim());
// this.CustID = new Guid(dr["CustID"].ToString().Trim());
// this.DeptID = new Guid(dr["DeptID"].ToString().Trim());
// this.DocTypeID = new Guid(dr["DocTypeID"].ToString().Trim());
// this.Name = dr["Name"].ToString().Trim();
// this.Title = dr["Title"].ToString().Trim();
// this.Tel = dr["Tel"].ToString().Trim();
// this.mtel = dr["mtel"].ToString().Trim();
// this.Fax = dr["Fax"].ToString().Trim();
// this.Addres = dr["Addres"].ToString().Trim();
// this.email = dr["email"].ToString().Trim();
// this.PostCode = dr["PostCode"].ToString().Trim();
// this.IsClose = bool.Parse(dr["IsClose"].ToString().Trim());
// this.TaxKind = int.Parse(dr["TaxKind"].ToString().Trim());
// this.Shop_ID = int.Parse(dr["Shop_ID"].ToString().Trim());
// this.ToWareHouse_ID = int.Parse(dr["ToWareHouse_ID"].ToString().Trim());
//}
#endregion
經測試速度還可以的,如果你說有用EF,Nhibernate 等主流的ORM,還用這個幹啥,當我大多情況下只需要讀數據,並且業務類比較少量,邏輯簡單的情況下 幹嘛還用搞nh,EF, 殺雞焉用牛刀呢,對吧,最主要是研究學習orm的功能,讀已經實現了,寫也就是個逆過程,以後有空有心情了留待實現吧,盡請期待<img alt="偷笑" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/titter.gif" />
</pre><pre name="code" class="csharp"><p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;"><strong><span style="color: rgb(51, 51, 255);"> 歡迎推薦一些開源的小系統,要求是能用,好用,方便,我有時間研究研究同時寫出使用心得,爲後來者快速入手帶來幫助。</span></strong></p><div><strong><span style="color: rgb(51, 51, 255);">
</span></strong></div>