您的位置:首页 > 其它

用反射实现将数据自动填充到对象中,学习orm的半个功能

2015-07-12 16:42 585 查看
最近整理以前的资料,想起来了这个小东西,以前感觉反射效率应该不行,后来翻看了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业务类定义



publicclass 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 staticSaleOrder GetDataByID(Guid ID)
{
try
{
string sqlstr = string.Format("select top 1 * from Inv_SaleOrder whereID='{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="https://oscdn.geek-share.com/Uploads/Images/Content/201707/33c29e3268d66ef5c09858efe40a3635.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>

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: