2010-03-07 24 views
21

Tengo una situación en la que estoy cargando un conjunto de registros muy normalizado de Excel. Tiro de cada fila y creo los objetos de uno en uno. cada fila podría contener una empresa y/o un cliente.C# fusionar dos objetos juntos en el tiempo de ejecución

Mi problema es que varias filas podrían tener los mismos objetos, por lo que puede que ya lo haya creado. Hago una comparación para ver si ya está en la lista. Si es así, necesito fusionar los dos objetos para asegurarme de que no obtuve ninguna información nueva de la segunda fila.

manera:

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

por lo que la primera fila sería crear un objeto de empresa con una dirección de "MiDirección". La segunda fila crearía otro objeto de compañía (que según mis reglas es la misma compañía ya que el nombre es el mismo), que también tiene una referencia de cliente y un número de teléfono.

Por lo tanto, yo sabría que son iguales pero es necesario garantizar que todos los datos se combinen en un solo objeto.

Por el momento estoy creando una clase de utilidad que toma ambos objetos, (uno es el primario y el otro para fusionarse, por lo que uno tiene prioridad si hay un conflicto), pasa por cada variable y asigna los valores si hay alguno. Esto es un poco pesado para la caldera y esperaba que pudiera haber alguna utilidad que pudiera utilizar para hacer el trabajo manual para mí.

El ejemplo se ha simplificado ya que hay algunas otras variables, algunos tipos básicos y otros que son elementos más complejos.

+0

¿Estás seguro de que siempre hay un máximo de 2 objetos que deben fusionarse? ¿Qué debería pasar si la misma columna/propiedad se define dos veces? ¿Suena peligroso solo para ignorar uno? – Achim

+0

Ellos están iterando a través de mis colecciones en el momento en que me fusionaría en cada partido encontrado. En teoría, podría haber múltiples coincidencias a través de la colección, pero cada fusión se haría de a una por vez. Si los usuarios han ingresado datos incorrectos, entonces tengo que perder algo de valor debido a la multiplicidad de campos que de todos modos no veo. – Jon

Respuesta

37

La reflexión funcionaría. Algo como:

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

Genérico y elegante. Pero de alguna manera hace que un escalofrío recorra mi espina dorsal. – CesarGon

+0

¡Muy buenos sombreros para usted señor! ;-) – BlackTea

+1

Por alguna razón, 'priValue == Activator.CreateInstance (pi.PropertyType)' devuelve falso para los tipos de valor. En cambio, 'priValue.Equals (Activator.CreateInstance (pi.PropertyType))' produce salida correcta. – Mrchief

1

Intente crear una tabla hash basada en cadenas. Utilice una concatenación de un subconjunto de campos que considere que activan un registro duplicado como clave. La tabla hash no permitirá duplicados, por lo que puede utilizar este error como desencadenador para realizar un procesamiento posterior.

0

Sin saber mucho más sobre su entorno y sus requisitos, esto puede ser inútil. Pero si tiene algún tipo de backend de base de datos disponible (incluso los del lado del cliente libres), puede almacenar los datos en una tabla y usar la declaración SQL Merge para actualizar los datos. Una operación de fusión agregará o actualizará un registro según sea necesario. Un gatillo podría refinar aún más la operación. Esta es una solución bastante pesada, pero si ya tiene un poco de DBMS en la mezcla, puede ser un método fácil de implementarlo.

3

Intentaré dividir esto: divide y conquista.

Primero, lea todos los objetos en una lista enorme.

En un segundo paso, seleccione listas distintas usando su clave principal, por ejemplo, el nombre de la compañía. De la lista distinta, use el elemento (el maestro) que tiene el mayor número de campos establecidos. Luego, itere sobre todos los campos que aún no están en el maestro y combine sus valores. LINQ le ayudará mucho en muchos de estos pasos sin la necesidad de codificar algoritmos complicados manualmente.

Esto permite personalizar la lógica fácilmente más tarde, p. Ej. si tiene un conjunto diferente de 'claves principales' por así decirlo o si desea hacer comparaciones especiales de campos particulares.

0

Al recuperar los datos de Excel, no es necesario crear un objeto para cada fila.De hecho, es probable que desee ir a una forma intermedia que lea todas las filas de adelante, luego crea los objetos desde allí. La solución de Kibbey usando tablas hash podría funcionar aquí también.

+0

Hola, lo siento, simplifiqué un poco mi ejemplo para facilitarlo. Leí todo el xls en una tabla de datos directamente y luego creé una estructura de cada fila para hacer mi procesamiento, en lugar de tratarlo directamente. – Jon

2

He intentado Merge Two Objects into an Anonymous Type por Kyle Finley y está funcionando perfecto.

Con la TypeMerger la fusión es tan simple como

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

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

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

Eso es lo que tiene el objeto fusionado, aparte de eso, hay una disposición a ignorar propiedades específicas también.

+1

¿Qué espacio de nombres es TypeMerger? Supongo que es un objeto personalizado porque no puedo encontrarlo incluso buscando en google. –

Cuestiones relacionadas