2010-03-07 115 views
21

我遇到了一种情况,那就是我从Excel中加载了一个非标准化的记录集。我拉动每一行,并逐个创建一个对象。每行可以包含公司和/或客户。C#在运行时将两个对象合并在一起

我的问题是多行可能有相同的对象,所以我可能已经创建它。我做了比较,看它是否已经在列表中。如果是这样,我需要合并这两个对象以确保我没有从第二行获得任何新信息。

这样:

company - client - address - phone 
---------------------------------------- 
mycompany -   - myaddress - 
mycompnay - myclient -   - myphone 

所以第一行会创建一个公司物体的“myaddress”的地址。 第二行将创建另一个公司对象(由我的规则是同一家公司,因为名称相同),这也有一个客户端引用和电话号码。

所以我会知道他们是一样的,但需要确保所有的数据合并成一个对象。

目前我正在创建一个实用程序类,它接受两个对象(一个是主合并,另一个是合并的,因此如果发生冲突,则优先),它会遍历每个变量并分配值如果有的话。这是一个沉重的锅炉板,我希望有一些工具可以用来为我做手动工作。

该示例已被简化,因为其他变量相当少,某些基本类型和其他更复杂的项目。

+0

你确定总是有最多2个对象需要合并吗?如果同一列/属性定义两次,会发生什么?听起来很危险,只是忽略一个!? – Achim 2010-03-07 14:33:26

+0

他们的方式我正在遍历我的集合,此刻我将在每个找到的匹配中进行合并。理论上可以通过集合进行多次匹配,但每次合并都会一次完成一次。如果用户输入错误的数据,以至于我不得不因为多个字段而失去一些价值,那么我无法看到它。 – Jon 2010-03-07 14:39:34

回答

37

反射会奏效。例如:

public static void MergeWith<T>(this T primary, T secondary) { 
    foreach (var pi in typeof(T).GetProperties()) { 
     var priValue = pi.GetGetMethod().Invoke(primary, null); 
     var secValue = pi.GetGetMethod().Invoke(secondary, null); 
     if (priValue == null || (pi.PropertyType.IsValueType && priValue.Equals(Activator.CreateInstance(pi.PropertyType)))) { 
      pi.GetSetMethod().Invoke(primary, new object[]{secValue}); 
     } 
    } 
} 
+7

通用和优雅。但不知怎的,它让我的脊椎颤抖起来。 – CesarGon 2010-03-07 14:19:37

+0

非常漂亮的帽子给你,先生! ;-) – BlackTea 2011-12-16 02:33:35

+1

出于某种原因,对于值类型,'priValue == Activator.CreateInstance(pi.PropertyType)'返回false。相反,'priValue.Equals(Activator.CreateInstance(pi.PropertyType))'产生正确的输出。 – Mrchief 2012-11-04 19:42:25

1

尝试创建一个基于字符串的哈希表。使用您认为是重复记录触发器的字段子集的串联作为密钥。哈希表将不允许重复,因此您可以将此错误用作执行进一步处理的触发器。

0

不知道更多关于您的环境和要求,这可能是没用的。但是,如果您有某种数据库后端可用(即使是免费的客户端数据库),您可以将数据存储在一个表中并使用SQL Merge语句更新数据。合并操作将根据需要添加或更新记录。触发器可以进一步细化操作。这是一个相当重量级的解决方案,但是如果你已经有了一些DBMS的话,它可能是一个实现它的简单方法。

3

我试图分裂它:分而治之。

首先,读取一个巨大列表中的所有对象。

第二步,使用主键选择不同的列表,例如公司名称。从不同的列表中,使用具有最多字段设置的项目(主)。然后,迭代所有尚未存在于主文件中的字段并合并它们的值。在许多步骤中,LINQ将帮助你很多,而无需手动编写复杂的算法。

这允许稍后自定义逻辑,例如,如果你有一套不同的'主键'可以这么说,或者你想对特定领域进行特殊比较。

0

当您从Excel中检索数据时,不需要为每行创建一个对象。事实上,您可能想要转到一个中间形式,先读取所有行,然后从中创建对象。 Kibbey使用散列表的解决方案也可以在这里工作。

+0

嗨,对不起,我简化了我的例子有些放松。我将整个xls读入数据表中,然后创建每行的结构来处理,而不是直接处理它。 – Jon 2010-03-07 14:48:10

2

我尝试过凯尔芬利的Merge Two Objects into an Anonymous Type,它工作的很完美。

随着TypeMerger合并很简单,只要

var obj1 = new {foo = "foo"};

var obj2 = new {bar = "bar"};

var mergedObject = TypeMerger.MergeTypes(obj1 , obj2);

就是这样,你得到的合并对象,除此之外,还有一项条款,忽视特定的属性。

+1

TypeMerger是什么命名空间?我假设它是一个自定义对象,因为即使通过搜索谷歌我也找不到它。 – 2013-06-30 02:39:55