一个通过反射实现的Domain Mode(持久化类) 和 Dto(数据传输类)实体转换,数组(Array)和列表(List)类型的封装类
时间:2010-09-15 来源:永恒的记忆
在我们使用Wcf+NHibernate+Spring结合时,通常需要两种类型进行手动赋值。这是一个通过反射实现的Domain Mode(持久化类) 和 Dto(数据传输类)实体转换,数组(Array)和列表(List)类型的封装类,可以方便地将两种类型互相转换,无需手动赋值。
例如:
一个用户实体
/// <summary>
/// 用户对象
/// </summary>
public class User : BaseDomain
{
/// <summary>
/// 用户ID
/// </summary>
public virtual long? UserID { get; set; }
/// <summary>
/// 所属部门
/// </summary>
public virtual Department CurrentDepartment { get; set; }
/// <summary>
/// 所属组
/// </summary>
public virtual Group CurrentGroup { get; set; }
/// <summary>
/// 用户名
/// </summary>
public virtual string UserName { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 用户密码
/// </summary>
public virtual string Password { get; set; }
/// <summary>
/// 用户描述
/// </summary>
public virtual string Description { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public virtual bool IsEnabled { get; set; }
/// <summary>
/// 密码恢复问题
/// </summary>
public virtual string Question { get; set; }
/// <summary>
/// 密码恢复答案
/// </summary>
public virtual string Answer { get; set; }
}
/// <summary>
/// 用户对象
/// </summary>
[DataContract]
[Serializable]
public class UserEntity : BaseDomain
{
/// <summary>
/// 用户ID
/// </summary>
[DataMember]
public virtual long? UserID { get; set; }
/// <summary>
/// 所属部门
/// </summary>
[DataMember]
public virtual long DepartmentID { get; set; }
/// <summary>
/// 所属组
/// </summary>
[DataMember]
public virtual long GroupID { get; set; }
/// <summary>
/// 用户名
/// </summary>
[DataMember]
public virtual string UserName { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
[DataMember]
public virtual string Name { get; set; }
/// <summary>
/// 用户密码
/// </summary>
[DataMember]
public virtual string Password { get; set; }
/// <summary>
/// 用户描述
/// </summary>
[DataMember]
public virtual string Description { get; set; }
/// <summary>
/// 是否启用
/// </summary>
[DataMember]
public virtual bool IsEnabled { get; set; }
/// <summary>
/// 密码恢复问题
/// </summary>
[DataMember]
public virtual string Question { get; set; }
/// <summary>
/// 密码恢复答案
/// </summary>
[DataMember]
public virtual string Answer { get; set; }
}
这两个实体,他们存在一种关系,但是UserEntity是用于在网络上传输的对象,而User则是我们要保存到数据库的对象,因此我们就要在服务器端手动赋值,如果使用下面的类,我们就无需这样手动赋值了。
数据转换类
public static class DataConverter
{
/// <summary>
/// 转换为持久化类
/// </summary>
/// <param name="entity"></param>
public static void ConvertToModel(this BaseDomain entity, BaseDomain model, IList<Func<BaseDomain>> fnList)
{
IEnumerable<BaseDomain> modelList = fnList.Select(li => li());
Type type = model.GetType();
foreach (PropertyInfo item in type.GetProperties())
{
//跳过系统属性
if (IsSystemProperty(item))
{
continue;
}
foreach (PropertyInfo property in entity.GetType().GetProperties())
{
if (property.Name == item.Name)
{
Type t = System.Nullable.GetUnderlyingType(property.PropertyType);
if (property.PropertyType == item.PropertyType || t != null)
{
item.SetValue(model, property.GetValue(entity, null), null);
}
continue;
}
if (item.Name.StartsWith("Current"))
{
string propertyName = item.Name.Replace("Current", "") + "ID";
string basePropertyName = item.PropertyType.BaseType.Name + "ID";
if (property.Name == propertyName || property.Name == basePropertyName)
{
foreach (BaseDomain refModel in modelList)
{
if (refModel == null)
{
continue;
}
if (refModel.GetType() == item.PropertyType
|| refModel.GetType().IsSubclassOf(item.PropertyType))
{
item.SetValue(model, refModel, null);
break;
}
}
}
}
}
}
}
//判断该属性是否是系统属性
private static bool IsSystemProperty(PropertyInfo item)
{
if (item.Name == "InsertTime" || item.Name == "UpdateTime" || item.Name == "Version")
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 转换为数据传输对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
public static T ConvertToEntity<T>(this BaseDomain entity) where T : BaseDomain
{
Type type = typeof(T); //获取类型
T result = (T)Activator.CreateInstance(type); //创建对象
//遍历属性
foreach (PropertyInfo item in type.GetProperties())
{
foreach (PropertyInfo property in entity.GetType().GetProperties())
{
//跳过空属性
if (property.GetValue(entity, null) == null)
{
continue;
}
if (property.Name == item.Name)
{
//相同属性赋值
if (property.PropertyType == item.PropertyType)
{
object value = property.GetValue(entity, null);
item.SetValue(result, value, null);
}
else
{
//字集合转换
if (property.Name == "Details")
{
//获取数组元素类型
Type t = item.PropertyType.GetElementType();
IList list = property.GetValue(entity, null) as IList;
//创建泛型集合实例
Type collectionType = Type.GetType(string.Format("System.Collections.Generic.List`1[[{0},{1}]]",
t.FullName, t.Assembly.FullName));
IList collection = Activator.CreateInstance(collectionType) as IList;
if (list != null && list.Count > 0 && t != null)
{
foreach (var li in list)
{
object value = Activator.CreateInstance(t);
if ((li as BaseDomain) != null)
{
foreach (var p in li.GetType().GetProperties())
{
//相同名称属性赋值
if (t.GetProperty(p.Name) != null)// && t == p.PropertyType)
{
t.GetProperty(p.Name).SetValue(value, p.GetValue(li, null), null);
continue;
}
//主键属性赋值
if (p.Name.StartsWith("Current"))
{
string propertyName = p.Name.Replace("Current", "") + "ID";
if ((t.GetProperty(propertyName) != null))
{
object obj = p.GetValue(li, null);
string name = propertyName == "OutStorehouseID" ? "StorehouseID" : propertyName;
PropertyInfo objProperty = p.PropertyType.GetProperty(name);
object v = objProperty.GetValue(obj, null);
t.GetProperty(propertyName).SetValue(value, v, null);
}
}
}
collection.Add(value as BaseDomain);
}
}
}
item.SetValue(result, collectionType.GetMethod("ToArray").Invoke(collection, new object[0]), null);
}
}
continue;
}
if (property.Name.StartsWith("Current"))
{
string propertyName = property.Name.Replace("Current", "") + "ID";
if (item.Name == propertyName)
{
object obj = property.GetValue(entity, null);
string name = propertyName == "OutStorehouseID" ? "StorehouseID" : propertyName;
PropertyInfo objProperty = property.PropertyType.GetProperty(name);
object value = objProperty.GetValue(obj, null);
item.SetValue(result, value, null);
}
}
}
}
return result;
}
//将List转换为Array
public static T[] ConvertToArray<T, TSource>(this IList<TSource> source)
where TSource : BaseDomain
where T : BaseDomain
{
var list = source.Select(li => li.ConvertToEntity<T>());
return list.ToArray();
}
}
在我们转换的时候
User model = this.userManager.New();
IList<Func<BaseDomain>> fnList = new List<Func<BaseDomain>>();
fnList.Add(() => this.departmentManager.Get(entity.DepartmentID));
fnList.Add(() => this.groupManager.Get(entity.GroupID));
entity.ConvertToModel(model, fnList);
这样就把UserEntity转换成User了