Microsoft ActiveX Data Objects 2.6 Library
y usar la directiva:
using ADODB;
El método que crea el recordset:
public static Recordset CrearRecordsetDesdeLista<T>(IEnumerable<T> lista) { Recordset rsParaVB6 = new Recordset(); rsParaVB6.CursorLocation = CursorLocationEnum.adUseClient; Fields rsColumnas = rsParaVB6.Fields; if (lista != null && lista.Count() > 0) { //Se elije un objeto no nulo. Si todos los objetos son nulos se obtendrá un null. T objNoNulo = lista.FirstOrDefault(x=> x != null); if (objNoNulo != null) { PropertyInfo[] arrPi = objNoNulo.GetType().GetProperties(); //Agrega las columnas for (int i = 0; i < arrPi.Length; i++) { Type tipoDotNet = arrPi[i].PropertyType; DataTypeEnum tipoADODB = Met_TraduceTipoDato(tipoDotNet); int lengthColumna = ObtenerMaxLenghtColumna(tipoDotNet, arrPi[i].GetValue(objNoNulo, null)); rsColumnas.Append(arrPi[i].Name, tipoADODB, lengthColumna , FieldAttributeEnum.adFldUpdatable, Missing.Value); } //Abre el recordset: rsParaVB6.Open(Missing.Value, Missing.Value, CursorTypeEnum.adOpenUnspecified, LockTypeEnum.adLockUnspecified, 0); //Agregando filas foreach (var obj in lista) { if (obj != null) { rsParaVB6.AddNew(Missing.Value, Missing.Value); //Agrega los valores a cada columna: for (int i = 0; i < arrPi.Length; i++) { rsColumnas[i].Value = arrPi[i].GetValue(obj, null); } rsParaVB6.Update(Missing.Value, Missing.Value); } } } } return rsParaVB6; }
En este método se llaman a otros 2 métodos:
/// <summary> /// Traduce el tipo de dato .Net al tipo de dato que usa ADODB.Recordset y retorna éste último. /// </summary> /// <param name="tipoDatoNet">Tipo de dato .Net a ser traducido.</param> /// <returns> /// Retorna un tipo de dato apropiado para ADODB.Recordset. /// </returns> protected static DataTypeEnum TraduceTipoDato(Type tipoDatoNet) { switch (tipoDatoNet.UnderlyingSystemType.ToString()) { case "System.Boolean": return ADODB.DataTypeEnum.adBoolean; case "System.Byte": return ADODB.DataTypeEnum.adUnsignedTinyInt; case "System.Char": return ADODB.DataTypeEnum.adChar; case "System.DateTime": return ADODB.DataTypeEnum.adDate; case "System.Decimal": return ADODB.DataTypeEnum.adCurrency; case "System.Double": return ADODB.DataTypeEnum.adDouble; case "System.Int16": return ADODB.DataTypeEnum.adSmallInt; case "System.Int32": return ADODB.DataTypeEnum.adInteger; case "System.Int64": return ADODB.DataTypeEnum.adBigInt; case "System.SByte": return ADODB.DataTypeEnum.adTinyInt; case "System.Single": return ADODB.DataTypeEnum.adSingle; case "System.UInt16": return ADODB.DataTypeEnum.adUnsignedSmallInt; case "System.UInt32": return ADODB.DataTypeEnum.adUnsignedInt; case "System.UInt64": return ADODB.DataTypeEnum.adUnsignedBigInt; case "System.String": default: return ADODB.DataTypeEnum.adVarChar; }//switch } /// <summary> /// Devuelve el MaxLength para una columna ADODBRecordset, en los DataColumn de .Net el MaxLength es considerado /// solo si el tipo es String de lo contrario no se toma en cuenta y el valor predeterminado es -1. /// <para> /// Ver: http://msdn.microsoft.com/es-es/library/system.data.datacolumn.maxlength%28v=vs.80%29.aspx /// </para> /// Si el tipo de dato es String entonces se devuelve el Length del parámetro <paramref name="valorDatoNet"/> /// </summary> /// <param name="tipoDatoNet">Tipo de dato .Net a verificar</param> /// <param name="valorDatoNet">Valor del tipo de dato a verificar</param> /// <returns> /// Retorna el Length de un valor siempre y cuando este sea de tipo /// String(si la cadena está vacía o nula el length a devolver será 1), de lo contrario devolverá -1. /// </returns> protected static int ObtenerMaxLenghtColumna(Type tipoDatoNet, object valorDatoNet) { int maxLength = -1; if ("System.String" == tipoDatoNet.UnderlyingSystemType.ToString()) { maxLength = valorDatoNet != null ? valorDatoNet.ToString().Length : 1; } return maxLength; }
La clase completa:
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using ADODB; namespace MyDLL { public class ADODBRecordsetCreator { //aquí van los 3 métodos expuestos líneas arriba. } }
Si asumimos que la clase ADODBRecordsetCreator-la cual contiene a los 3 métodos listados arriba- se encuentra en la librería MyDLL, podemos utilizar dicha librería más o menos así:
using System.Collections.Generic; using TestDataAccess; using ADODB; using MyDLL; namespace TestRecordSet { class Program { static void Main(string[] args) { List<Producto> lista = new List<Producto>() { new Producto(){Codigo = "000001",Nombre="Producto 1",Precio=100}, new Producto(){Codigo = "000022",Nombre="Producto 2",Precio=220}, new Producto(){Codigo = "000333",Nombre="Producto 3",Precio=333} }; Recordset rsParaVB6; rsParaVB6 = MyHelpers.CrearRecordsetDesdeLista(lista); } } public class MyHelpers { public static Recordset CrearRecordsetDesdeLista<T>(IEnumerable<T> lista) { return ADODBRecordsetCreator.CrearRecordsetDesdeLista(lista); } } [Serializable] public class Producto { public string Codigo { get; set; } public string Nombre { get; set; } public decimal Precio { get; set; } } }