我有两个大型集合List<Class>
,其中包含数百个属性。
例如原始馆藏List<OriginalCollection>
和更新馆藏List<UpdatedColleciton>
UpdatedCollection
将包含某些列中的值,这些列很可能不是OriginalCollection
的一部分,并且UpdatedCollection
可能具有某些可能不属于OriginalCollection
的键列[ID列],并且我正在OriginalCollection
中接收数千个数据集,并且UpdatedColletion
记录将在一段时间内增加。
我确实有一个要求,只有空或空的OriginalCollection
列应该被替换为 ID 匹配UpdatedCollection
值,如果没有匹配的 ID 可用,那么这些记录应该从 UpdatedCollection
OriginalCollection
中添加。
我尝试使用 AutoMapper
,我试图根据匹配的 ID 使用UpdatedCollection
更新OriginalCollection
,为此我找不到上述要求集的任何AutoMapper configuration
。
我正在寻找不影响性能的最有效的解决方案,这就是为什么我没有抛出典型的联合和交叉方式,因为 Modal 有数百个属性和数千条记录,而且因为我确实有很多属性我认为像AutoMapper
这样的库是不错的选择,而不是在循环中编写逻辑来检查所有数千条记录的每一列的值。
请建议任何更好且性能高效的解决方案,例如自动映射器配置或任何其他 .Net 内置功能来实现此方案。
我还从 https://github.com/AutoMapper/AutoMapper.Collection 中检查了以下AutoMapper.Collection
cfg.CreateMap<OrderItemDTO, OrderItem>().EqualityComparison((odto, o) => odto.ID == o.ID);
Mapping OrderDTO back to Order will compare Order items list based on if their ID's match
Mapper.Map<List<OrderDTO>,List<Order>>(orderDtos, orders);
但它有以下行为,并且没有按照我的要求正常工作
- 如果 ID 的匹配项将订单DTO映射到订单
- 如果 OrderDTO 存在并且 Order 未添加到集合中 对我不起作用
- 如果订单存在并且 OrderDTO 未从集合中删除 对我不起作用
AutoMapper
是已知的映射库,也有很好的文档,但无法找到类似的详细文档AutoMapper.Collection
,我已经探索了AutoMapper.Collection
但它没有按照我的要求提供解决方案。所以,我需要走传统的方式。
通过LINQ
查询准备收集差异。
var common = original.Where(x => revised.Exists(z => z.ID == x.ID)).ToList();
var nonCommon = revised.Where(x => !original.Exists(z => z.ID == x.ID)).ToList();
foreach(var item in common)
{
var derived = revised.FirstOrDefault(x => x.ID == item.ID);
// Added Extention Method to compare and update property
var data = item.UpdateProperties(derived);
}
common.AddRange(nonCommon);
利用反射来比较对象,并在属性级别比较后更新其值,适用于所有数据类型。
public static T UpdateProperties<T>(this T source, T destination)
{
Type type = source.GetType(); // Gets Source Object Type
PropertyInfo[] props = type.GetProperties(); // Gets Source object Properties
foreach (var prop in props) // Iterate threw all properties of source object
{
var sourceValue = prop.GetValue(source); // Get source object value by Property Name
var destinationValue = prop.GetValue(destination); // Get destination object value by Property Name, to update source object
// Update source object property value only if derived object's property has value and source object doesn't
if (string.IsNullOrEmpty(sourceValue?.ToString()) && !string.IsNullOrEmpty(destinationValue?.ToString()))
{
prop.SetValue(source, destinationValue); // Update source object's property with value of derived object
}
}
return source;
}