映射时设置对象的嵌套属性
set nested properties of object while mapping
我使用表达式树作为自动映射器的替代方法,使用以下代码将源属性映射到目标属性
我正在做的是,我在 static class 中创建了静态方法,用于将内部子对象 属性 映射和分配给外部对象 属性
public static class PropertyMapper<TSource, TDest>
{
private static Expression<Func<TSource, Dictionary<string, MasterSection>, TDest>> _mappingExpression;
private static Func<TSource, Dictionary<string, MasterSection>, TDest> _mapper;
static PropertyMapper()
{
_mappingExpression = ProjectionMap();
_mapper = _mappingExpression.Compile();
}
public static Func<TSource, Dictionary<string, MasterSection>, TDest> Mapper => _mapper;
public static Expression<Func<TSource, Dictionary<string, MasterSection>, TDest>> ProjectionMap()
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
var targetProperties= typeof(TDest).GetProperties().Where(p => p.CanWrite);
var propertyMap =
from d in targetProperties
join s in sourceProperties on new { d.Name, d.PropertyType } equals new { s.Name, s.PropertyType }
where d.Name != "SourceOfDataId" && d.Name!= "SourceOfData"
select new { Source = s, Dest = d };
var itemParam = Expression.Parameter(typeof(TSource), "item");
var memberBindings = propertyMap.Select(p => (MemberBinding)Expression.Bind(p.Dest, Expression.Property(itemParam, p.Source))).ToList();
var sourceOfDataIdProp = targetProperties.FirstOrDefault(s => s.Name == "SourceOfDataId");
if (sourceOfDataIdProp != null)
{
memberBindings.Add(Expression.Bind(sourceOfDataIdProp,Expression.Convert(Expression.Property(Expression.Property(itemParam, "SourceOfData"),"Id"),typeof(Guid?))));
}
var sourceOfDataProp = targetProperties.FirstOrDefault(s => s.Name == "SourceOfData");
if(sourceOfDataProp != null)
{
// here i would like to update `sourceOfData` object property "isApproved"
}
var newExpression = Expression.New(typeof(TDest));
var memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
var projection = Expression.Lambda<Func<TSource, Dictionary<string, MasterSection>, TDest>>(memberInitExpression, itemParam, dictParam);
return projection;
}
}
我在下面使用上述方法将源属性映射到目标属性
AirflowsLab = sourceMechanicalData.AirflowsLab.Select(a => PropertyMapper<LibraryLabAirflow, LibraryLabAirflow>.Mapper(a, masterSectionMappedLibrary)).ToList();
LibraryLabAirflow 的结构如下所示
public class LibraryLabAirflow
{
[ForeignKey("SourceOfData")]
public Guid? SourceOfDataId { get; set; }
public virtual CodeStandardGuideline SourceOfData { get; set; }
}
上面的映射工作正常,我正在尝试的是现在我需要访问目标的 sourceOfData
子对象并更新 sourceOfData
的 属性 和更新的映射子对象到源子对象 sourceOfData
.
下面是 sourceOfData 对象的详细信息
"SourceOfData":{
"Id": "c5bf3585-50b1-4894-8fad-0ac884343935",
"IsApproved": null, // trying to set this to true instead of null inside target object
"MasterSection": null
},
我不确定在这种情况下如何使用表达式树访问子对象 属性,而且我不能使用 automapper 库。谁能告诉我如何访问子对象 属性 并更新并分配回目标。
我试图生成的表达式看起来像这样 source.SourceOfData = target.SourceOfData
但在此之前我需要更新 target.SourceOfData
的 属性 之一
非常感谢
想要表达 :
AirflowsLab = sourceMechanicalData.AirflowsLab.Where(a => a != null).Select(item => new LibraryLabAirflow()
{
SourceOfData = new CodeStandardGuideline()
{
IsApproved = true,// trying to set this through expression tree
City = item.SourceOfData.City
......
.......
}
}).ToList(),
这样尝试也不行,1
var sourceOfDataProp = targetProperties.FirstOrDefault(s => s.Name == "SourceOfData");
if(sourceOfDataProp != null)
{
// here need to get the sourceofdata properties
var sourceOfDataProperty = Expression.Property(Expression.Constant(sourceOfDataProp), "IsApproved");
}
更新:
我已经在 sourceOfDataProp != null
的 if 块中实现了逻辑,但出现错误
if (sourceOfDataProp != null)
{
var targetitemParam = Expression.Parameter(typeof(TTarget), "item");
var sourceOfDataPropertiesFilter = new List<string>()
{
"IsApproved"
};
var sourceItem = Expression.Property(itemParam, typeof(TSource).GetProperty("SourceOfData"));
var sourcePropertyInfo = sourceItem.Type.GetProperties().Where(p => p.CanRead);
var targetItem = Expression.Property(targetitemParam, typeof(TTarget).GetProperty("SourceOfData"));
var targetPropertyInfo = targetItem.Type.GetProperties().Where(p => p.CanWrite);
var sourceOfDataPropertyMap = from tp in targetPropertyInfo
join sp in sourcePropertyInfo
on new { tp.Name, tp.PropertyType } equals new { sp.Name, sp.PropertyType }
where !sourceOfDataPropertiesFilter.Contains(tp.Name)
select new { Source = sp, Target = tp };
// getting error at below line type of arguments does not match
var sourceOfDataMemberBindings = sourceOfDataPropertyMap.Select(p => Expression.Bind(p.Target, Expression.PropertyOrField(targetitemParam, "SourceOfData"))).ToList();
}
我已经解决了这个问题,如下所示
if (sourceOfDataProp != null)
{
var targetItemParam = Expression.Parameter(typeof(TTarget), "item");
var sourceOfDataPropertiesFilter = new List<string>()
{
"IsApproved"
};
var sourceItem = Expression.Property(itemParam, typeof(TSource).GetProperty("SourceOfData"));
var sourceOfDataSourceProperties = sourceItem.Type.GetProperties().Where(p => p.CanRead);
var targetItem = Expression.Property(targetItemParam, typeof(TTarget).GetProperty("SourceOfData"));
var sourceOfDataTargetProperties = targetItem.Type.GetProperties().Where(p => p.CanWrite);
var sourceOfDataPropertyMap = sourceOfDataTargetProperties.Join(sourceOfDataSourceProperties,
t => new { t.Name, t.PropertyType },
s => new { s.Name, s.PropertyType },
(t, s) => new { Source = s, Target = t })
.Where(t => !sourceOfDataPropertiesFilter.Contains(t.Target.Name));
var sourceOfDataMemberBindings = sourceOfDataPropertyMap.Select(p => Expression.Bind(p.Target, Expression.Property(sourceItem, p.Source))).ToList();
var sourceOfDataIsApprovedProp = sourceOfDataTargetProperties.FirstOrDefault(s => s.Name == "IsApproved");
if (sourceOfDataIsApprovedProp != null)
{
sourceOfDataMemberBindings.Add(Expression.Bind(sourceOfDataIsApprovedProp, Expression.Constant(true, typeof(bool?))));
}
var sourceOfDataExpression = Expression.New(typeof(DesignHub.Entities.CodeStandardGuideline));
var sourceOfDataMemberInitExpression = Expression.MemberInit(sourceOfDataExpression, sourceOfDataMemberBindings);
memberBindings.Add(Expression.Bind(sourceOfDataProp, sourceOfDataMemberInitExpression));
}
我使用表达式树作为自动映射器的替代方法,使用以下代码将源属性映射到目标属性
我正在做的是,我在 static class 中创建了静态方法,用于将内部子对象 属性 映射和分配给外部对象 属性
public static class PropertyMapper<TSource, TDest>
{
private static Expression<Func<TSource, Dictionary<string, MasterSection>, TDest>> _mappingExpression;
private static Func<TSource, Dictionary<string, MasterSection>, TDest> _mapper;
static PropertyMapper()
{
_mappingExpression = ProjectionMap();
_mapper = _mappingExpression.Compile();
}
public static Func<TSource, Dictionary<string, MasterSection>, TDest> Mapper => _mapper;
public static Expression<Func<TSource, Dictionary<string, MasterSection>, TDest>> ProjectionMap()
{
var sourceProperties = typeof(TSource).GetProperties().Where(p => p.CanRead);
var targetProperties= typeof(TDest).GetProperties().Where(p => p.CanWrite);
var propertyMap =
from d in targetProperties
join s in sourceProperties on new { d.Name, d.PropertyType } equals new { s.Name, s.PropertyType }
where d.Name != "SourceOfDataId" && d.Name!= "SourceOfData"
select new { Source = s, Dest = d };
var itemParam = Expression.Parameter(typeof(TSource), "item");
var memberBindings = propertyMap.Select(p => (MemberBinding)Expression.Bind(p.Dest, Expression.Property(itemParam, p.Source))).ToList();
var sourceOfDataIdProp = targetProperties.FirstOrDefault(s => s.Name == "SourceOfDataId");
if (sourceOfDataIdProp != null)
{
memberBindings.Add(Expression.Bind(sourceOfDataIdProp,Expression.Convert(Expression.Property(Expression.Property(itemParam, "SourceOfData"),"Id"),typeof(Guid?))));
}
var sourceOfDataProp = targetProperties.FirstOrDefault(s => s.Name == "SourceOfData");
if(sourceOfDataProp != null)
{
// here i would like to update `sourceOfData` object property "isApproved"
}
var newExpression = Expression.New(typeof(TDest));
var memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
var projection = Expression.Lambda<Func<TSource, Dictionary<string, MasterSection>, TDest>>(memberInitExpression, itemParam, dictParam);
return projection;
}
}
我在下面使用上述方法将源属性映射到目标属性
AirflowsLab = sourceMechanicalData.AirflowsLab.Select(a => PropertyMapper<LibraryLabAirflow, LibraryLabAirflow>.Mapper(a, masterSectionMappedLibrary)).ToList();
LibraryLabAirflow 的结构如下所示
public class LibraryLabAirflow
{
[ForeignKey("SourceOfData")]
public Guid? SourceOfDataId { get; set; }
public virtual CodeStandardGuideline SourceOfData { get; set; }
}
上面的映射工作正常,我正在尝试的是现在我需要访问目标的 sourceOfData
子对象并更新 sourceOfData
的 属性 和更新的映射子对象到源子对象 sourceOfData
.
下面是 sourceOfData 对象的详细信息
"SourceOfData":{
"Id": "c5bf3585-50b1-4894-8fad-0ac884343935",
"IsApproved": null, // trying to set this to true instead of null inside target object
"MasterSection": null
},
我不确定在这种情况下如何使用表达式树访问子对象 属性,而且我不能使用 automapper 库。谁能告诉我如何访问子对象 属性 并更新并分配回目标。
我试图生成的表达式看起来像这样 source.SourceOfData = target.SourceOfData
但在此之前我需要更新 target.SourceOfData
非常感谢
想要表达 :
AirflowsLab = sourceMechanicalData.AirflowsLab.Where(a => a != null).Select(item => new LibraryLabAirflow()
{
SourceOfData = new CodeStandardGuideline()
{
IsApproved = true,// trying to set this through expression tree
City = item.SourceOfData.City
......
.......
}
}).ToList(),
这样尝试也不行,1
var sourceOfDataProp = targetProperties.FirstOrDefault(s => s.Name == "SourceOfData");
if(sourceOfDataProp != null)
{
// here need to get the sourceofdata properties
var sourceOfDataProperty = Expression.Property(Expression.Constant(sourceOfDataProp), "IsApproved");
}
更新:
我已经在 sourceOfDataProp != null
的 if 块中实现了逻辑,但出现错误
if (sourceOfDataProp != null)
{
var targetitemParam = Expression.Parameter(typeof(TTarget), "item");
var sourceOfDataPropertiesFilter = new List<string>()
{
"IsApproved"
};
var sourceItem = Expression.Property(itemParam, typeof(TSource).GetProperty("SourceOfData"));
var sourcePropertyInfo = sourceItem.Type.GetProperties().Where(p => p.CanRead);
var targetItem = Expression.Property(targetitemParam, typeof(TTarget).GetProperty("SourceOfData"));
var targetPropertyInfo = targetItem.Type.GetProperties().Where(p => p.CanWrite);
var sourceOfDataPropertyMap = from tp in targetPropertyInfo
join sp in sourcePropertyInfo
on new { tp.Name, tp.PropertyType } equals new { sp.Name, sp.PropertyType }
where !sourceOfDataPropertiesFilter.Contains(tp.Name)
select new { Source = sp, Target = tp };
// getting error at below line type of arguments does not match
var sourceOfDataMemberBindings = sourceOfDataPropertyMap.Select(p => Expression.Bind(p.Target, Expression.PropertyOrField(targetitemParam, "SourceOfData"))).ToList();
}
我已经解决了这个问题,如下所示
if (sourceOfDataProp != null)
{
var targetItemParam = Expression.Parameter(typeof(TTarget), "item");
var sourceOfDataPropertiesFilter = new List<string>()
{
"IsApproved"
};
var sourceItem = Expression.Property(itemParam, typeof(TSource).GetProperty("SourceOfData"));
var sourceOfDataSourceProperties = sourceItem.Type.GetProperties().Where(p => p.CanRead);
var targetItem = Expression.Property(targetItemParam, typeof(TTarget).GetProperty("SourceOfData"));
var sourceOfDataTargetProperties = targetItem.Type.GetProperties().Where(p => p.CanWrite);
var sourceOfDataPropertyMap = sourceOfDataTargetProperties.Join(sourceOfDataSourceProperties,
t => new { t.Name, t.PropertyType },
s => new { s.Name, s.PropertyType },
(t, s) => new { Source = s, Target = t })
.Where(t => !sourceOfDataPropertiesFilter.Contains(t.Target.Name));
var sourceOfDataMemberBindings = sourceOfDataPropertyMap.Select(p => Expression.Bind(p.Target, Expression.Property(sourceItem, p.Source))).ToList();
var sourceOfDataIsApprovedProp = sourceOfDataTargetProperties.FirstOrDefault(s => s.Name == "IsApproved");
if (sourceOfDataIsApprovedProp != null)
{
sourceOfDataMemberBindings.Add(Expression.Bind(sourceOfDataIsApprovedProp, Expression.Constant(true, typeof(bool?))));
}
var sourceOfDataExpression = Expression.New(typeof(DesignHub.Entities.CodeStandardGuideline));
var sourceOfDataMemberInitExpression = Expression.MemberInit(sourceOfDataExpression, sourceOfDataMemberBindings);
memberBindings.Add(Expression.Bind(sourceOfDataProp, sourceOfDataMemberInitExpression));
}