Como obtener el Connection String clásico con Entity Framework

por Andres Stang  28. enero 2011

Como sabrán Entity Framework utiliza un conection string para saber con qué base de datos trabajar, el tema es que además de contener la cadena de conexión que conocemos de toda la vida, tiene un poco más de información que utiliza para indicarle otras cosas que no vienen al caso.

Si quisiéramos recuperar la clásica cadena de conexión para, por ejemplo, no utilizar Entity Framework y acceder directamente a la base de datos con ADO.NET uno pensaria en hacer:

 

   1:  MiModeloEntities miEntities = new MiModeloEntities();
   2:  string connStringEF = miEntities.Connection.ConnectionString;

 

Pero no nos serviría! Ya que tenemos la cadena de conexión de Entity Framework que incluye metadata que antes mencionamos. Ya sé, seguramente ya estás pensando en usar expresiones regulares… Momento! La solución? Simplemente:

 

   1:  MiModeloEntities miEntities = new MiModeloEntities();
   2:  string connString = ((System.Data.EntityClient.EntityConnection)miEntities.Connection).StoreConnection.ConnectionString;

 

Y de esta manera nos evitamos tener duplicada la información en nuestra configuración y evitamos parsear el string innecesariamente.

Tags: ,

.NET | Entity Framework | ORM | SQL Server

El Datawarehouse de TFS no se actualiza luego de un upgrade a SQL Server 2008

por Victor Passador  19. julio 2010

Días pasados, en el proceso de upgrade de un servidor a TFS 2010, comenzamos con la actualización del motor de base de datos a su versión 2008, uno de los prerrequisitos exigidos.

Si bien el servidor estaba virtualizado y ante algún imprevisto podríamos restaurar rápidamente un backup reciente de esa VM, decidimos tomar una precaución adicional que fue esperar un par de días luego de ese upgrade antes de encarar la instalación de la nueva versión de TFS, para ver si algún usuario informaba de inconvenientes.

Ya decididos a instalar TFS 2010, un PM nos informa que los reportes de los diferentes proyectos estaban mostrando datos viejos. La espera no había sido en vano.

Lo primero que hicimos fue forzar la actualización del Datawarehouse (aquí hemos descripto cómo hacerlo), pero sin éxito.

SQL Management Studio por su parte, informaba las bases de datos de Analysis Services estaban funcionando correctamente, pero los datos aún no se actualizaban.

Sin mensajes de error, la búsqueda de ayuda en Internet se complicaba. No aparecían casos similares en los buscadores, hasta que mirando en el Log de Eventos del SO dimos con algunas palabras claves que nos condujeron a un artículo de Bill Wang.

Básicamente el problema era que, luego del upgrade a SQL Server 2008, TFS seguía intentando conectarse a Analisys Services pero de la versión 2005, y allí se producía el fallo.

Para solucionar el inconveniente, hay que reemplazar una entrada del Web Config del WS de TFS como a continuación se detalla:

Reemplazar …

   1: <dependentAssembly>
   2:         <assemblyIdentity name="Microsoft.AnalysisServices"
   3:                           publicKeyToken="89845dcd8080cc91"
   4:                           culture="neutral" />
   5:         <bindingRedirect oldVersion="9.0.242.0" newVersion="9.0.242.0"/>
   6: </dependentAssembly>

… por …

   1: <dependentAssembly>
   2:         <assemblyIdentity name="Microsoft.AnalysisServices"
   3:                           publicKeyToken="89845dcd8080cc91"
   4:                           culture="neutral" />
   5:         <bindingRedirect oldVersion="9.0.242.0" newVersion="10.0.0.0"/>
   6: </dependentAssembly>

Tener en cuenta que además, la herramienta “SetupWarehouse.exe” también accede al cubo de la misma forma, con lo cual deberá modificarse el archivo “SetupWarehouse.exe.config”.

Tags: , ,

Gestión de Proyectos | SQL Server | TFS

Cuál es la mejor forma de realizar procesos batch con Entity Framework?

por Daniel Laco  16. abril 2010

Es muy común que en las aplicaciones sea necesario realizar procesos de actualizaciones masivas. Siempre está la tentación de usar EF para hacer estos procesos, ya que es muy fácil buscar y actualizar registros. Pero en el caso de EF el costo que se paga por toda la infraestructura que tiene es muy alto.

En el caso de procesos masivos, si hay que actualizar o borrar un registro, primero hay que traerlo (esto implica que EF mantenga el tracking con el ObjectStateManager) posteriormente hacer la actualización o borrado y por último realizar la actualización con el ObjectContext.

Resumiento, para realizar procesos batch lo mejor es NO USAR Entity Framework !!

Pero que opciones tengo entonces?

Voy a mostrar 2 alternativas de las muchas que hay, simulando que hay que leer un archivo .TXT de longitud fija  y posteriormente hay que realizar una actualización de miles de registros en una tabla de la base de datos.

El escenario es que recibo un archivo con códigos de productos de la empresa y códigos de productos de proveedores externos. El proceso que hay que realizar es: leer el archivo y actualizar los códigos de de los proveedores externos en cada registro de los productos de la empresa.

Para esto usaremos como ayuda la excelente libreria FileHelpers realizada por Marcos Meli

El formato en que viene el archivo es el siguiente:

 

/// <summary>
/// Archivo de Unión de Códigos de Productos de la Empresa y Proveedores
/// </summary>
 
[FixedLengthRecord(FixedMode.AllowLessChars)]
public class UnionProductos
{
    [FieldFixedLength(7)]
    public int EmpresaCodigo;
 
    [FieldFixedLength(7)]
    public string Proveedor1Codigo;
 
    [FieldFixedLength(7)]
    public int Proveedor2Codigo;
 
}

 

El proceso de lectura con FileHelpers:

FileHelperEngine engine = new FileHelperEngine(typeof(UnionProductos));
UnionProductos[] UnionLeido = engine.ReadFile(nombreArchivo) as UnionProductos[];
 
 

Opción 1

Recorrer el array de Productos y ejecutar un Store Procedure con la actualización correspondiente:

 

string stringDeConexion = "XXXXXXXXXXXXXXXX";
using (SqlConnection conn = new SqlConnection(stringDeConexion))
{
    conn.Open();
    SqlCommand cmd = new SqlCommand("nombreStore", conn);
    cmd.Parameters.Add("@empresaCodigo", SqlDbType.Int);
    cmd.Parameters.Add("@proveedor1Codigo", SqlDbType.VarChar);
    cmd.Parameters.Add("@proveedor2Codigo", SqlDbType.Int);
 
 
    foreach (UnionProductos producto in UnionLeido)
    {
        cmd.Parameters[0].Value = producto.EmpresaCodigo;
        cmd.Parameters[1].Value = producto.Proveedor1Codigo;
        cmd.Parameters[2].Value = producto.Proveedor2Codigo;
 
        cmd.ExecuteNonQuery();
 
    }
}

 

Por supuesto el Store hace algo asi como:

UPDATE Productos 
SET Proveedor1Codigo = @proveedor1Codigo, 
    Proveedor2Codigo = @proveedor2Codigo
WHERE Productos.Codigo = @empresaCodigo

 

Opción 2

Esta es la mas performante de las 3 opciones. El único problema es que solo es posible en SQL Server 2008.

Está implementada utilizando una Tabla como Parámetro y realizando toda la actualización mediante una sentencia SQL.

Veamos como hacelo:

Se crea un tipo de dato Table en SQLServer

CREATE TYPE UnionProductosTbl AS TABLE 
(
    EmpresaCodigo int,
    Proveedor1Codigo varchar(7),
    Proveedor2Codigo int
)

 

Se crea el Procedimiento Almacenado usando ese tipo como parámetro:

CREATE PROCEDURE ActualizarCodigosProveedores
    @unionProductosTbl dbo.UnionProductosTbl READONLY
AS
BEGIN
 
    UPDATE Productos p
    SET p.Proveedor1Codigo = tbl.Proveedor1Codigo,
    p.Proveedor2Codigo = tbl.Proveedor2Codigo
    FROM Productos
    INNER JOIN @unionProductosTbl tbl ON p.Codigo = tbl.empresaCodigo
    
END

 

Y el proceso en el código:

//Lectura del Archivo
               FileHelperEngine engine = new FileHelperEngine(typeof(UnionProductos));
               //Devuelve como DataTable
               DataTable unionLeidoDT = engine.ReadFileAsDT(nombreArchivo);
 
               //El proceso de actualización
               string stringDeConexion = "XXXXXXXXXXXXXXXX";
               using (SqlConnection conn = new SqlConnection(stringDeConexion))
               {
                   conn.Open();
                   SqlCommand cmd = new SqlCommand("nombreStore", conn);
                   //Se define un parámetro de tipo Structured para que reciba un DataTable
                   SqlParameter par = cmd.Parameters.Add("@unionProductosTbl", 
                       SqlDbType.Structured);
                   par.Value = unionLeidoDT;
                   cmd.ExecuteNonQuery();
               }
               
 

Realizando el proceso con 17.000 registros los resultados fueron los siguientes (los tiempos son orientativos):

Opción Tiempo

Utilizando EF

8 minutos

Utilizando ADO.NET nativo procesando registro a registro con un Store Procedure

4 minutos

Utilizando un Store Procedure en SQL 2008 con una tabla como parámetro

4 segundos !!

 

Para finalizar, la opción de realizar el proceso batch usando una tabla como parámetro de un Store es la mejor opción si la prioridad es la performance de la solución.

Tags: ,

ADO.NET | Entity Framework | SQL Server

Como depurar Store Procedures, Triggers y Functions de SQL Server desde Visual Studio 2008

por emmanuel  22. marzo 2010

Una tarea imprescindible en el desarrollo y programación con SQL Server es la depuración (debugging) de Store Procedures, Triggers y Functions. El debugging nos permite ejecutar paso a paso código T-SQL, establecer breakpoints, examinar el contenido de las variables y modificarlos en tiempo de depuración, etc.

Anteriormente, los desarrolladores escribían y depuraban con el Analizador de consultas de SQL Server 2000 (Query Analyzer).

Luego, el SQL Server Management Studio 2005 que lo reemplazó no tenía ningún depurador, por lo cual para poder depurar código T-SQL se utilizaba el depurador que tiene el Visual Studio 2005.

A partir de la versión 2008 de SQL Server, las capacidades de debugging ya vienen incluidas en el Management Studio (solo funcionan con una conexión contra una instancia
de SQL Server 2008), sin embargo en ciertas ocasiones es más conveniente utilizar Visual Studio para el debugging de objetos de SQL.

Requerimientos

  • Versión Professional o Team Edition de Visual Studio.
  • Es importante destacar que al depurar se detendrán todos los threads de ejecución de SQL, de modo que no es recomendable depurar en un servidor que se encuentre en producción.
  • Activar el debugging de CLR en SQL: para esto se debe primero crear una conexión a la base de datos mediante la ventana "Server Explorer" (Menú "View"). Luego dar click derecho sobre la conexión y tildar la opción "Allow SQL/CLR Debugging"

 

EnableDebugging

Permisos

Para poder depurar código SQL desde Visual Studio 2008 existen dos cuentas de usuario para considerar:

  • La cuenta de la aplicación: es la cuenta de usuario sobre la cual se ejecuta Visual Studio. Esta cuenta es una cuenta de usuario de Windows, y debe ser miembro del grupo sysadmin en el SQL Server a ser depurado.
  • La cuenta de conexión: es la identidad usada para conectarse con SQL Server (Definida en el dialogo de conexión del "Server Explorer", o en el connection string). Esta cuenta puede ser una cuenta de usuario de Windows usando Windows Authentication (en este caso es la misma sobre la cual corre Visual Studio), o puede ser una cuenta de conexión SQL, en cuyo caso debe ser miembro del rol sysadmin para poder depurar.

 

Si no se cumplen los permisos requeridos para la Depuración de SQL Server, y se intenta depurar código de SQL Server, se obtiene el siguiente error:
User 'dbo' could not execute stored procedure 'master.dbo.sp_enable_sql_debug' on SQL Server VSQL01.

Pasos para la depuración

  • Ubicar el objeto a depurar en la ventana "Server Explorer".
  • Dar click derecho sobre el objeto que se desea depurar y seleccionar "Step into ..." ("Step into Store Procedure", "Step into Function", etc.)

 

StepInto 

  • Si requiere parámetros, aparecerá un cuadro de diálogo que permite asignar los valores para cada parámetro.

 

Parametros

  • En todo momento se puede visualizar o modificar el valor de variables locales, para lo cual podemos utilizar la ventana "Locals" de Visual Studio, disponible el menú "Debug" (solo cuando la depuración ha sido iniciada), o también mediante la ventana "Watch".

 

Debug

 

 

  • Para depurar un Trigger, se debe tener en cuenta que no se le puede invocar directamente, por lo cual, lo que se puede hacer es crear un Store Procedure cuyo código fuente invoque al Trigger, y utilizar Step Into (F11 - paso a paso por instrucciones) en vez de Step Over (F10 - paso a paso por el proceso actual) para la depuración, de manera de entrar en el código del Trigger en cuestión.

 

image

En el ejemplo se muestra un store procedure que ejecuta un UPDATE sobre la tabla que tiene el trigger a depurar. Al presionar F11 sobre la instrucción UPDATE se ingresa en modo depuración al código del trigger.

 

image

Tags: ,

SQL Server

Scripts seguros: Una historia de Transacciones, Stored Procedures y GOs

por leonardo  19. marzo 2010

Cuando trabajamos con bases de datos, tarde o temprano llega la necesidad de tener que preparar scripts para actualizar el modelo de datos en el cliente, en un servidor no accesible, etc. Esto trae una carga importante de riesgos, sobre todo de pérdida de información o de dejar la base en un estado inconsistente.

Para asegurarnos de que todo quede en un estado conocido, en principio podemos abrir una transacción y poner todo el script en un bloque TRY-CATCH como este:

BEGIN TRY
    BEGIN TRANSACTION
    --
    -- Poner acá el script con los cambios de la base
    --
    -- Aceptar los cambios de la transacción
 
    COMMIT TRANSACTION
END TRY
 
BEGIN CATCH
    -- Deshacer los cambios de la transacción
    ROLLBACK TRANSACTION
    --
    -- Manejar el error o relanzarlo
    --
END CATCH

Ahora, supongamos que nuestros cambios son los siguientes:

CREATE TABLE Sucursales (
    IdAlmacen INT,
    Direccion VARCHAR(100)
)
GO
 -- Otros cambios
GO
 
DELETE Articulos
WHERE IdCategoria = 9999
GO
 
-- Cambios sensibles y peligrosos
GO
CREATE PROCEDURE HacerNegocios AS
BEGIN
    --
    -- Aca va la formula mágica de cada uno
    --
END
GO
 
-- ...mas cambios peligrosos!
GO

 

Para ponerlo dentro del bloque TRY-CATCH, la única consideración seria borrar los "GO" ya que sino la transacción y el TRY quedarían incompletos, y el script no ejecutaría correctamente.

Nota: La palabra "GO" no es parte del lenguaje TSQL sino un comando (bastante estándar) interpretado por las aplicaciones como un separador de lotes de instrucciones. Para mas información: http://msdn.microsoft.com/es-es/library/ms188037.aspx .

Con esto surge un problema, el CREATE/ALTER PROCEDURE (también aplicado a Functions y Triggers) debe ser la primera instrucción del lote debido a una restricción de sintáxis de SQL Server

Para salvar este inconveniente, una solución es ejecutar la creación del stored procedure con Dynamic SQL. Quedando asi:

EXEC(N'CREATE PROCEDURE HacerNegocios AS
BEGIN
    --
    -- aqui va la formula magica de cada uno
    --
    SELECT * FROM CC
END')

Con esto, no hay ningún problema de crear o modificar un stored procedure dentro de una transacción.

BEGIN TRY
    BEGIN TRANSACTION
    
    CREATE TABLE Sucursales (
    IdAlmacen INT,
    Direccion VARCHAR(100)
    )
 
    -- Otros cambios
 
    DELETE Articulos
    WHERE IdCategoria = 9999
 
    -- Cambios sensibles y peligrosos
 
    EXEC(N'CREATE PROCEDURE HacerNegocios AS
    BEGIN
        --
        -- aqui va la formula mágica de cada uno
        --
    END')
 
    -- ...mas cambios peligrosos!
    
    -- Aceptar los cambios de la transacción
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    -- Deshacer los cambios de la transacción
    ROLLBACK TRANSACTION
 
    --
    -- Manejar el error o relanzarlo
    --
END CATCH
 

Espero que este pequeño "truco" facilite la generación de scripts para hacer actualizaciones en las bases de datos.

Tags:

SQL Server

Acerca de los Autores

Este es el blog del equipo de VEMN SA 
Presentaremos temas que nos parezcan de interés sobre tecnología .NET, Procesos y Metodologías y todo aquello relacionado con el proceso de desarrollo de Software

Month List

BlogRoll

Download OPML file OPML