如以下贴出的代码:
我的需求就是,Entity是针对数据库存储的,DTO是针对业务数据传输的。
我就是想把Entity和DTO之间的转换封装起来,但是如果DTO之间存在关联的时候,转换的时候就会有递归调用的问题,我不想每次在业务层读取Entity之后再把对应的属性依次复制到DTO上面,把Entity和DTO的转换进行内部封装,就不用每次都做重复的事情。看来我现在的方案行不通,希望各位园友提供更好的思路。
对于我现在的处理方式,可能会在FromEntity里面复制一般属性,比如像List<OrgNode>这种关系的,留在业务层那里,根据业务场景,做出相应的复制或者加载。
各位请多多指教^_^
示例代码:
///////////////////////////////////////// Entity 代码 //////////////////////////////
public class OrgChart { public int Id { get; set; } public string Name { get; set; } public OrgNode Root { get; set; } public IList<OrgNode> Nodes { get; set; } } public class OrgNode { public int Id { get; set; } public string Name { get; set; } public string Type { get; set; } public OrgChart Chart { get; set; } public OrgNode Parent { get; set; } public IList<OrgNode> ChildNodes { get; set; } }
///////////////////////////////////////// DTO代码 //////////////////////////////
public interface IBaseDTO<T> { T ToEntity(); void FromEntity(T entity); } public class OrgChartDTO : IBaseDTO<OrgChart>{ public int Id { get; set; } public string Name { get; set; } public OrgNodeDTO Root { get; set; } public IList<OrgNodeDTO> Nodes { get; set; } public OrgChart ToEntity() { //省略 } public void FromEntity(OrgChart entity) { //其他属性 if(entity.Root != null) { this.Root = new OrgNodeDTO(); //#关键代码! //1.当Root(OrgNode)调用FromEntity方法则进入OrngNode的FromEntity(看一下OrgNode代码) this.Root.FromEntity(entity); } } } public class OrgNodeDTO : IBaseDTO<OrgNode>{ public int Id { get; set; } public string Name { get; set; } public string Type { get; set; } public OrgChartDTO Chart { get; set; } public OrgNodeDTO Parent { get; set; } public IList<OrgNodeDTO> ChildNodes { get; set; } public OrgNode ToEntity() { //省略 } public void FromEntity(OrgNode entity) { //其他属性 if(entity.Chart != null) { OrgChartDTO chartDTO = new OrgChartDTO(); //#关键代码! //2.因为OrgNode关联OrgChart,所以从OrgChart的Root.FromEntity()之后,就不停的递归。 // OrChart.FormEntity->Root.FromEntity->Root.OrgChart.FromEntity->OrgChart.Root.FromEntity->..., // 直到StackOverflowException. chartDTO.FromEntity(entity.Chart); this.Chart = chartDTO; } } }
用 AutoMapper。
这个真心强大,非常感谢!
automapper 好像不能忽略源对象中null属性
https://github.com/AutoMapper/AutoMapper/issues/1406
/// <summary>
/// Dto对象转Entity,只是复制属性,dto的属性要比entity少2个哦。
/// </summary>
/// <typeparam name="T">EntityObject</typeparam>
/// <param name="dto">dto对象</param>
/// <returns>EntityObject对应的实例</returns>
public EntityObject ConvertToEntityObject<T>(object dto) where T : EntityObject
{
Type dtoEntity = dto.GetType();
var piList = dtoEntity.GetProperties().Where(p => p.PropertyType.IsPublic == true).ToList();
Assembly assembly = Assembly.GetAssembly(typeof(T));
object resultObj = assembly.CreateInstance(string.Join(".",new string[]{typeof(T).Namespace,typeof(T).Name}));
var piResultObj = resultObj.GetType().GetProperties().Where(p => p.PropertyType.IsPublic == true).ToList();
foreach (System.Reflection.PropertyInfo pi in piList)
{
var sourcePi = piResultObj.Single(p => p.Name == pi.Name);
if (sourcePi != null)
{
object value = pi.GetValue(dto, null);
sourcePi.SetValue(resultObj, value, null);
}
}
return resultObj as EntityObject;
}
目前有更好的方案,自己写反射暂时不考虑,谢谢^_^