visual studio net llenar epass ejemplos ejemplo desde c# vb6 performance

c# - studio - Convertir conjunto de registros COM de ADO 2.8 persistente en ADO.Net DataSet



sqldataadapter c# ejemplos (4)

Si está diciendo que todo el conjunto de registros COM se está conservando en una sola columna en la tabla de la base de datos como un objeto binario (matriz de bytes), entonces no veo ninguna forma de evitar la complejidad. Debe convertir el conjunto de bytes en el mismo objeto concreto desde el que se serializó (un conjunto de registros COM), antes de poder manipularlo.

Tengo una aplicación VB6 que estoy convirtiendo a .net. Lo hago en fases para que los clientes tengan aplicaciones VB6 y .net al mismo tiempo. Parte de la aplicación almacena en caché los conjuntos de registros COM de ADO 2.8 en una tabla en SQL Server y los recupera según sea necesario. La aplicación .net usa los mismos conjuntos de registros persistentes. Tengo el código c # que recupera el conjunto de registros persistentes y lo convierte en un conjunto de datos. Mi pregunta es: ¿Lo estoy haciendo de la manera más eficiente?

Este es mi código que recupera el conjunto de registros de la base de datos -

Stream adoStream = null; SqlParameter cmdParameter; SqlCommand cmd = null; SqlDataReader dr = null; string cmdText; int bytesReturned; int chunkSize = 65536; int offSet = 0; UnicodeEncoding readBytes; try { cmdParameter = new SqlParameter(parameterName, idParamter); cmdText = sqlString; cmd = new SqlCommand(); cmd.CommandType = CommandType.Text; cmd.CommandTimeout = 0; cmd.CommandText = cmdText; cmd.Connection = this.pbiSQLConnection; cmd.Parameters.Add(cmdParameter); dr = cmd.ExecuteReader(CommandBehavior.SequentialAccess); dr.Read(); if (dr.HasRows) { readBytes = new UnicodeEncoding(); byte[] byteChunk = new byte[chunkSize]; adoStream = new Stream(); adoStream.Type = StreamTypeEnum.adTypeText; adoStream.Open(Type.Missing, ConnectModeEnum.adModeUnknown, StreamOpenOptionsEnum.adOpenStreamUnspecified, "", ""); do { bytesReturned = (int)dr.GetBytes(0, offSet, byteChunk, 0, chunkSize); size += bytesReturned; if (bytesReturned > 0) { if (bytesReturned < chunkSize) { Array.Resize(ref byteChunk, bytesReturned); } adoStream.WriteText(readBytes.GetString(byteChunk), StreamWriteEnum.stWriteChar); adoStream.Flush(); } offSet += bytesReturned; } while (bytesReturned == chunkSize); } } catch (Exception exLoadResultsFromDB) { throw (exLoadResultsFromDB); } finally { if (dr != null) { if (!dr.IsClosed) { dr.Close(); } dr.Dispose(); } if (cmd != null) { cmd.Dispose(); } }

Este es el código que convierte la secuencia de ado a un conjunto de datos:

adoStream = LoadTextFromDBToADODBStream(resultID, "@result_id", "some sql statement", ref size); if (adoStream.Size == 0) { success = false; } else { adoStream.Position = 0; DataTable table = new DataTable(); Recordset rs = new Recordset(); rs.Open(adoStream, Type.Missing, CursorTypeEnum.adOpenStatic, LockTypeEnum.adLockBatchOptimistic, -1); if (adoStream != null) { adoStream.Close(); adoStream = null; } source.SourceRows = rs.RecordCount; table.TableName = "Source"; source.Dataset = new DataSet(); source.Dataset.Tables.Add(table); OleDbDataAdapter adapter = new OleDbDataAdapter(); adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; adapter.Fill(source.Dataset.Tables[0], rs); if (adapter != null) { adapter.Dispose(); adapter = null; } if (adoStream != null) { adoStream.Close(); adoStream = null; } if (rs != null) { if (rs.State == 1) { rs.Close(); } rs = null; } }

Gracias a todos

EDITAR: Agregué una recompensa para ver si alguien puede hacer que el código sea más eficiente.


No responde su pregunta específica ... pero como está especificando la eficiencia, supongo que quiere velocidad.
¿Pensó en persistir dos veces, tanto como ADO y ADO.Net, entonces, el solicitante podría recuperar el más apropiado y omitir la conversión en tiempo de ejecución (esto es asumiendo muchas más lecturas que escrituras). Para obtener un impulso adicional, tal vez almacene una cantidad n de conjuntos de datos en la memoria, donde pueden devolverse al instante en lugar de volver a cargarlos desde la base de datos. Nuevamente, esto solo sería útil dependiendo de sus datos y solicitudes específicos.


El código parece bastante eficiente en general. Si bien estoy de acuerdo con la necesidad de tener rutinas de manejo de COM generalizadas (solo por coherencia, si nada más), no sé qué rendimiento extra extraerá de su recomendación de no reutilizar la conexión de DB.

Lo único de lo que me preocuparía es que estés usando ADO Stream. Este objeto en particular tiene un pequeño efecto secundario de comer memoria como un niño en una tienda de dulces. Verificaría este artículo ( http://www.vbrad.com/article.aspx?id=12 ) y me aseguraré de que tu código no tenga este problema.


En general, no está aprovechando lo suficiente la declaración de uso y no la está manejando usted mismo. Desafortunadamente, lo está haciendo de la manera incorrecta, ya que si tiene una implementación de IDisposable que arroja una excepción en la llamada a Dispose, las otras llamadas a Dispose no tienen lugar. Si usa la instrucción using, se invocarán todas las implementaciones de IDisposable.Dispose, sin importar cuán anidadas estén.

Pasemos primero por LoadTextFromDBToADODBStream. El problema masivo aquí es que estás compartiendo una conexión cuando no deberías. Debería crear la conexión para su operación, usarla y luego cerrarla. Ese no es el caso aquí.

Así que supongamos que creas tu conexión en un método diferente, como este:

SqlConnection CreateConnection() { // Create the connection here and return it. return ...; }

También necesitará la siguiente estructura para gestionar adecuadamente sus referencias COM:

struct ComReference<T> : IDisposable where T : class, new() { private T reference; public T Reference { get { return reference; } } public static ComReference<T> Create() { // Create the instance. ComReference<T> retVal = new ComReference<T>(); // Set the reference. retVal.reference = new T(); // Return. return retVal; } public ComReference<T> Release() { // Create a copy for return. // Note, this is copied on the stack. ComReference<T> retVal = this; // Set this reference to null; this.reference = null; // Return the reference. return retVal; } public void Dispose() { // If there is a reference, then release. Marshal.ReleaseComObject(reference); } }

Desea administrar sus referencias COM con esto para que las libere cuando haya terminado con ellas, no a través de la recolección de elementos no utilizados. COM se basa en la finalización determinista, y no puede ignorar eso solo porque está en .NET. La estructura anterior aprovecha el IDisposable (y el hecho de que es una estructura y los matices que lo acompañan) para ayudar a hacerlo de una manera determinista.

El parámetro de tipo T será el tipo de clase que se crea para la interoperabilidad COM, en el caso de la secuencia, será ADODB.StreamClass.

Su LoadTextFromDBToADODBStream se ve así:

ComReference<StreamClass> LoadTextFromDBToADODBStream(int idParameter, string parameterName, string sqlString, ref int size) { int bytesReturned; int chunkSize = 65536; int offSet = 0; // Create the command. using (SqlCommand cmd = new SqlCommand()) { // Set the parameters. cmd.CommandType = CommandType.Text; cmd.CommandTimeout = 0; cmd.CommandText = sqlString; // See (1). using (SqlConnection connection = CreateConnection()) { // Set the connection on the command. cmd.Connection = connection; // Create the parameter and add to the parameters. SqlParameter cmdParameter = new SqlParameter( parameterName, idParameter); cmd.Parameters.Add(cmdParameter); // Create the reader. using (SqlDataReader dr = cmd.ExecuteReader( CommandBehavior.SequentialAccess)) { dr.Read(); // See (2) if (!dr.HasRows) { // Return an empty instance. return new ComReference<StreamClass>(); } // Create the stream here. See (3) using (ComReference<StreamClass> adoStreamClass = ComReference<StreamClass>.Create()) { // Get the stream. StreamClass adoStream = adoStreamClass.Reference; // Open the stream. adoStream.Type = StreamTypeEnum.adTypeText; adoStream.Open(Type.Missing, ConnectModeEnum.adModeUnknown, StreamOpenOptionsEnum.adOpenStreamUnspecified, "", ""); // Create the byte array. byte[] byteChunk = new byte[chunkSize]; // See (4) Encoding readBytes = Encoding.Unicode; // Cycle. do { bytesReturned = (int)dr.GetBytes(0, offSet, byteChunk, 0, chunkSize); size += bytesReturned; if (bytesReturned > 0) { if (bytesReturned < chunkSize) { Array.Resize(ref byteChunk, bytesReturned); } adoStream.WriteText( readBytes.GetString(byteChunk), StreamWriteEnum.stWriteChar); adoStream.Flush(); } offSet += bytesReturned; } while (bytesReturned == chunkSize); // Release the reference and return it. // See (5). return adoStreamClass.Release(); } } } } }

Notas:

  1. Aquí es donde quieres crear tu conexión. Desea usarlo en una declaración de uso porque quiere estar seguro de que sus recursos están limpios, en caso de éxito o fracaso.
  2. Es más fácil cortocircuitar el código aquí y devolver una nueva instancia de ComReference<StreamClass> . Cuando creas esto, tiene el efecto de devolver una estructura que no tiene referencia (que es lo que quieres, en lugar de llamar al método estático de Crear).
  3. Al llamar al método Create estático, está creando la nueva instancia de ADODB.StreamClass. Desea asegurarse de que si algo sale mal, se elimine al momento de la publicación (ya que es una implementación de interfaz COM y depende de la finalización determinista).
  4. No es necesario crear un nuevo UnicodeEncoding. Puede usar la propiedad Unicode en la clase de Codificación para usar una instancia prefabricada.
  5. En la versión de llamada, establece el campo de referencia en nulo en la instancia que está en la pila actual, y lo transfiere a la ComReference<StreamClass> que se devuelve. De esta forma, la referencia de StreamClass sigue activa, y cuando se invoca a Dispose en la variable de pila, no pasa esa referencia a ReleaseComObject.

Pasando al código que llama LoadTextFromDBToADODBStream:

// See (1) using (ComReference<StreamClass> adoStreamClass = LoadTextFromDBToADODBStream(resultID, "@result_id", "some sql statement", ref size)) { // Set to the class instance. See (2) StreamClass adoStream = adoStreamClass.Reference; if (adoStream.Size == 0) { success = false; } else { adoStream.Position = 0; DataTable table = new DataTable(); // See (3) using (ComReference<RecordsetClass> rsClass = ComReference<RecordsetClass>.Create()) { Recordset rs = rsClass.Reference; rs.Open(adoStream, Type.Missing, CursorTypeEnum.adOpenStatic, LockTypeEnum.adLockBatchOptimistic, -1); if (adoStream != null) { adoStream.Close(); adoStream = null; } source.SourceRows = rs.RecordCount; table.TableName = "Source"; source.Dataset = new DataSet(); source.Dataset.Tables.Add(table); // See (4) using (OleDbDataAdapter adapter = new OleDbDataAdapter()) { adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; adapter.Fill(source.Dataset.Tables[0], rs); } } } }

  1. Esto va a recibir el valor de retorno de la llamada a Release en LoadTextFromDBToADODBStream. Contendrá la referencia en vivo al ADODB.Stream creado allí, y la instrucción using garantizará que se borre cuando se deje el alcance.
  2. Como antes, esto hace que sea más fácil hacer referencia a la referencia directa, en lugar de tener que llamar siempre a adoStreamClass.Reference.<method>
  3. Usando otra ComReference, esta vez ComReference<RecordsetClass> .
  4. Deje que el compilador haga el trabajo sucio por usted.

Al usar la instrucción using más, puede limpiar gran parte del código que dificultaba la lectura. Además, en general, estaba solucionando algunos problemas de recursos que surgirían ante la excepción, así como las implementaciones COM manejadas que no se estaban eliminando correctamente.