C# merge two objects together at runtime
I have a situation where I am loading a very unnormalized record set from Excel. I pull in each row and create the objects from it one at a time. each row could contain a company and / or a client.
My issue is that multiple rows could have the same objects, so I may have already created it. I do a comparison to see if it is already in the list. If so I need to merge the two objects to ensure I have not gained any new information from the second row.
so:
company - client - address - phone
----------------------------------------
mycompany - - myaddress -
mycompnay - myclient - - myphone
so the first row would create a company object with an address of "myaddress". The second row would create another company object (which by my rules is the same company as the name is the same), this also having a client reference and a phone number.
So I would know they are the same but need to ensure all the data is merged into one object.
At the moment I am creating a utility class that takes both objects, (one being the primary and the other to be merged, so one has priority if there is a clash), it goes through each variable and assi开发者_StackOverflow中文版gns the values if there are any. This is a bit boiler plate heavy and I was hoping there might be some utility I could utilize to do the manual work for me.
The example has been simplified as there are a fair few other variables, some basic types and others that are more complex items.
Reflection would work. Something like:
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});
}
}
}
I'd try to split this up: divide and conquer.
First, read all the objects in one huge list.
In a second step, select distinct lists using your primary key, for example, the company name. From the distinct list, use the item (the master) that has the largest number of fields set. Then, iterate over all the fields that are not yet in the master and merge their values in. LINQ will help you a lot in many of these steps without the need to code complicated algorithms manually.
This allows to customize the logic easily later, e.g. if you have a different set of 'primary keys' so to speak or if you want to do special comparisons of particular fields.
Try creating a string based hash table. Use a concatenation of a subset of fields that you consider to be the trigger for a duplicate record as the key. The hashtable won't allow duplicates so you can use this error as a trigger to perform further processing.
Without knowing a lot more about your environment and requirements, this may be of no use. But if you have some kind of database back-end available (even free client-side ones), you could store the data in a table and use the SQL Merge statement to update the data. A merge operation will either add or update a record as needed. A trigger could further refine the operation. This is a rather heavyweight solution, but if you already have some DBMS in the mix, it may be an easy method of implementing it.
When you retrieve the data from Excel, there is no need to create an object for each row.In fact, you'd probably want to go to an intermediate form that reads all the rows up front, then it creates the objects from there. Kibbey's solution using hash tables could work here as well.
精彩评论