lunes, 18 de octubre de 2010

Acceder a Métodos, Controles o propiedades de un formulario hijo a uno padre. [Windows Forms] C# VB.Net

El día de hoy comentare sobre un caso muy usual al trabajar con aplicaciones WindowsForms, por lo menos para mi en .Net 2003, 2005 y 2008.

En el caso que revisare mediante un ejemplo muy sencillo tenemos:

a) Un formulario principal, que alberga un GridControl, y un método de agregado de filas al DataTable que alimenta ese GrigControl.

b) Un formulario secundario que se crea como un objeto desde el formulario principal, y desde el cuál se invocara el método de agregado de filas del GridControl del formulario principal.

1. Como dije, tenemos un DataTable a nivel de clase:

Private dt As New DataTable()

2. Y en el Evento Load del Formulario principal, armamos la estructura de la tabla y agregamos unos registros de prueba :

Try
           dt.Columns.Add(New DataColumn("a"))
           dt.Columns.Add(New DataColumn("b"))
           dt.Columns.Add(New DataColumn("c"))

           dt.Rows.Add("1", "2", "3")
           dt.Rows.Add("4", "5", "6")
           dt.Rows.Add("7", "8", "9")
           dt.Rows.Add("10", "11", "12")

           gc1.DataSource = dt

       Catch ex As Exception
           MsgBox(ex.Message)
       End Try

3. Como dije anteriormente, tenemos un método para agregar nuevos registros al DataTable:

Public Sub addRow(ByVal val1 As String, ByVal val2 As String, ByVal val3 As String)
        Try
            dt.Rows.Add(val1, val2, val3)

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

4. Ahora bien, si este método es llamado desde el formulario principal pues todo va bien, pero si instanciamos un nuevo formulario:

Dim f As New Form4
        f.Owner = Me
        f.Show()

lo más seguro es que estando en el formulario secundario, estemos tentados a invocar al método, de la siguiente manera:

Form2.addRow(TextBox3.Text, TextBox4.Text, TextBox5.Text)

con lo cual, en tiempo de compilación no tendremos ningún problema, sin embargo cuando realicemos el compilado de la aplicación, al ejecutar la aplicación, el método no funciona correctamente. ¿Porqué?

Bueno, pues porque no podemos acceder a los formulario y sus propiedades hacia arriba de forma directa, por lo que es necesario realizar un <casting> obteniendo el nombre del formulario principal, de la propiedad “owner”:

CType(Me.Owner, Form2).addRow(TextBox3.Text, TextBox4.Text, TextBox5.Text)

con lo cual el problema queda resuelto.

Como siempre espero que en algún momento les sea de utilidad

Best regards And Happy coding.

KarlozArba

miércoles, 13 de octubre de 2010

Formateo de campos Fecha–Hora para Sql Server desde .Net

Este post pretendo que sea breve ya que solo es para comentar que en ocasiones nos encontramos el problema de insertar o actualizar datos Datetime desde aplicaciones hechas con Vb.Net o C# y estos marcan error si no son recibidos como parámetros Sql debido a que llevan el formato 01-10-2010 02:30 p.m. por lo que SQL Server no puede interpretar las cadenas (a.m. | p.m.).

Esta situación la podemos solvertar de la siguiente forma:

VarriableDateTime.ToString("yyyyMMdd hh:mm:ss")

en un Ejemplo sencillo:

string sql = "UPDATE zabp_tareas_ogerp ";
sql += string.Format(" SET TIEMPO_INICIO = '{0}', TIEMPO_FIN = '{1}',HORA_LIBERACION = {2}",P_Hora_Inicio.ToString("yyyyMMdd hh:mm:ss"), P_Hora_Fin.ToString("yyyyMMdd hh:mm:ss"), P_Duracion);
sql += string.Format(" WHERE FOLIO={0}",P_Folio);

Donde podemos observar como se formatea de la forma: 20101001 14:30:00 con lo que eliminamos el problema.

Como siempre espero que les sea de utilizada.

Best regards And Happy coding.

KarlozArba

viernes, 8 de octubre de 2010

Crear tabla en sql server desde una instruccion select

 

En esta ocasión quiero compartirles algo que suele ser muy necesario cuando queremos respaldar los datos de una tabla especifica, sin tener que hacer backup de la BD completa, o cuando necesitamos guardar solo ciertos datos pero no conocemos a priori la estructura que tendrán esos datos e incluso quizá este proceso deba hacerse de forma dinámica por lo que ni siquiera sabemos en que momento se generara.

Bueno la forma es muy sencilla y es la siguiente:

SELECT [*|| campo1, campo2, campo3… campo(n)]

INTO NombreTablaNuevaOTemporal

FROM TablaOrigen

La explicación más sencilla aún:

Realizamos un SELECT tal y como lo necesitemos pero después del listado del campos necesarios, usaremos la palabra reservada INTO que permite la creación de una tabla con el nombre que señalemos a continuación de dicha instrucción. Quizá la pregunta sea: ¿´Qué pasa cuando la tabla ya existe y contiene datos?, bueno pues, esa tabla y datos son respetados, agregando únicamente los nuevos registros.

Bien, para finalizar un ejemplo sencillo:

SELECT t.FOLIO, t.ASUNTO

INTO test_table FROM zabp_tareas_ogerp t

WHERE  t.PARA='Desarrollo-Carlos Armenta'

Debido a que todo se hace desde un SELECT, podemos hacerlo tan complejo como sea necesario.

Best regards And Happy coding.

KarlozArba

jueves, 6 de mayo de 2010

Cambiar nombre a un campo, en Sql Server 2008

 

 

 

 

 

Bueno este es mi segundo post, y en esta ocasión mencionare algo que es muy sencillo pero que no en muchas ocasiones sabemos como hacerlo, bueno me refiero a: “Cambiar el nombre de un Campo en una tabla de Sql Server 2008”.

 

Realmente es una trabajo muy sencillo, basta con ejecutar el siguiente Store Procedure:

 

 

sp_rename [ @objname = ] 'nombre_objeto , [ @newname = ] 'nuevo_nombre' [ ,

[ @objtype = ] 'tipo_objeto ]

 

Donde:

nombre_objeto: se refiere al objeto al que necesitamos cambiar el nombre.

nuevo_nombre: nuevo identificador para el objeto.

tipo_objeto: es el tipo del objeto que deseamos renombrar.

 

Como se pueden imaginar este SP nos es útil para cambiar el nombre de Columnas, Indices, Tipos de Datos de Usuario, Bases de Datos y cualquier cosa que este en sys.objects.

 

Para nuestro caso usaremos algo como:

 

EXEC sp_rename 'CO.tbl_chk_out_hst.id_chk_out', 'id_chk_out_hst', 'COLUMN';

GO

 

Algo que les recomiendo es que aunque no sea obligatorio el uso de Schema.Tabla, ustedes lo utilizen a fin de que los nombres de objetos puedan estar bien calificados.

 

Finalizando y como recomendación, recordar que si modifican el nombre de una campo, deberan revisar a priori el impacto sobre otros objetos de la BD como vistas, stores, etc, así como sus aplicaciones.

 

Bien pues espero que les sea de utilidad.

 

"May the force be with you, and happy coding".

miércoles, 14 de abril de 2010

Meet to DDL Triggers

 

 

 

 

 

En el día a día de la administración de las bases de datos, los cambios en el schema son demasiados, por lo que se vuelve sumamente necesario contar con un mecanismo de auditoria de dichos cambios, que permita dar respuesta a las preguntas ¿qué? ¿como? ¿cuando? ¿quien? WTF?, y que eventualmente también te permitirá echarle la culpa al verdadero responsable de una catástrofe en las BD.

Bueno en este y otros escenarios más o menos parecidos tienen significado los DDL (Data Definition Language) Triggers, los cuales al igual que los DML Triggers se disparan al generarseciertos eventos en ciertos objetos, es decir, nosotros crearemos un Trigger que realize "algo" en el momento que tenga lugar un suceso determinado en el objeto de la BD que nos interese.

Estos Trigger (a partir de este momento TR) tienen 2 ambitos: Servidor y Base de Datos, y como es de esperarse responden a diferentes eventos.

 

Tabla de Eventos para la BD. (MSDN)

 

CREATE_APPLICATION_ROLE (Applies to CREATE APPLICATION ROLE statement andsp_addapprole. If a new schema is created, this event also triggers a CREATE_SCHEMA event.)

ALTER_APPLICATION_ROLE (Applies to ALTER APPLICATION ROLE statement andsp_approlepassword.)

DROP_APPLICATION_ROLE (Applies to DROP APPLICATION ROLE statement andsp_dropapprole.)

CREATE_ASSEMBLY

ALTER_ASSEMBLY

DROP_ASSEMBLY

ALTER_AUTHORIZATION_DATABASE (Applies to ALTER AUTHORIZATION statement when ON DATABASE is specified, and sp_changedbowner.)

   

CREATE_CERTIFICATE

ALTER_CERTIFICATE

DROP_CERTIFICATE

CREATE_CONTRACT

DROP_CONTRACT

 

GRANT_DATABASE

DENY_DATABASE

REVOKE_DATABASE

CREATE_EVENT_NOTIFICATION

DROP_EVENT_NOTIFICATION

 

CREATE_FUNCTION

ALTER_FUNCTION

DROP_FUNCTION

CREATE_INDEX

ALTER_INDEX

DROP_INDEX

CREATE_MESSAGE_TYPE

ALTER_MESSAGE_TYPE

DROP_MESSAGE_TYPE

CREATE_PARTITION_FUNCTION

ALTER_PARTITION_FUNCTION

DROP_PARTITION_FUNCTION

CREATE_PARTITION_SCHEME

ALTER_PARTITION_SCHEME

DROP_PARTITION_SCHEME

CREATE_PROCEDURE

ALTER_PROCEDURE

DROP_PROCEDURE

CREATE_QUEUE

ALTER_QUEUE

DROP_QUEUE

CREATE_REMOTE_SERVICE_BINDING

ALTER_REMOTE_SERVICE_BINDING

DROP_REMOTE_SERVICE_BINDING

CREATE_ROLE (Applies to CREATE ROLE statement, sp_addrole, and sp_addgroup.)

ALTER_ROLE

DROP_ROLE (Applies to DROP ROLE statement,sp_droprole, and sp_dropgroup.)

CREATE_ROUTE

ALTER_ROUTE

DROP_ROUTE

CREATE_SCHEMA (Applies to CREATE SCHEMA statement, sp_addrole, sp_adduser,sp_addgroup, and sp_grantdbaccess.)

ALTER_SCHEMA (Applies to ALTER SCHEMA statement and sp_changeobjectowner.)

DROP_SCHEMA

CREATE_SERVICE

ALTER_SERVICE

DROP_SERVICE

CREATE_STATISTICS

DROP_STATISTICS

UPDATE_STATISTICS

CREATE_SYNONYM

DROP_SYNONYM

 

CREATE_TABLE

ALTER_TABLE

DROP_TABLE

CREATE_TRIGGER

ALTER_TRIGGER

DROP_TRIGGER

CREATE_TYPE (Applies to CREATE TYPE statement and sp_addtype.)

DROP_TYPE (Applies to DROP TYPE statement andsp_droptype.)

 

CREATE_USER (Applies to CREATE USER statement, sp_adduser, andsp_grantdbaccess.)

ALTER_USER

DROP_USER (Applies to DROP USER statement,sp_dropuser, and sp_revokedbaccess.)

CREATE_VIEW

ALTER_VIEW

DROP_VIEW

CREATE_XML_SCHEMA_COLLECTION

ALTER_XML_SCHEMA_COLLECTION

DROP_XML_SCHEMA_COLLECTION

 

Tabla de Eventos a nivel del Servidor. (MSDN)

ALTER_AUTHORIZATION_SERVER

   

CREATE_DATABASE

ALTER_DATABASE

DROP_DATABASE

CREATE_ENDPOINT

ALTER_ENDPOINT

DROP_ENDPOINT

CREATE_LOGIN (Applies to CREATE LOGIN statement, sp_addlogin,sp_grantlogin, xp_grantlogin, and sp_denylogin when used on a nonexistent login that must be implicitly created.)

ALTER_LOGIN (Applies to ALTER LOGIN statement, sp_defaultdb,sp_defaultlanguage, sp_password, and sp_change_users_loginwhen Auto_Fix is specified.)

DROP_LOGIN (Applies to DROP LOGIN statement, sp_droplogin, sp_revokelogin, and xp_revokelogin.)

GRANT_SERVER

DENY_SERVER

REVOKE_SERVER

 

 

EVENTDATA()

 

Bien, cuando los eventos mencionados se disparan, la información que detalla lo ocurrido es almacenada en un archivo XML y que es accesible mediante la función EVENTDATA(), a partir de ahí podemos ocupar XQUERY, para consultar la información que necesitemos de forma especifica.

 

A continuación les muestro un ejemplo de la información proporcionada por EVENTDATA(). (Fuente)

 

 

<EVENT_INSTANCE>
<EventType>CREATE_TABLE</EventType>
<PostTime>2005-07-30T10:48:52.537</PostTime>
<SPID>55</SPID>
<ServerName>PSE-TEST-JON1</ServerName>
<LoginName>PSE-TEST-JON1\Administrator</LoginName>
<UserName>dbo</UserName>
<DatabaseName>AdventureWorks</DatabaseName>
<SchemaName>Person</SchemaName>
<ObjectName>Address</ObjectName>
<ObjectType>TABLE</ObjectType>
<TSQLCommand>
<SetOptions ANSI_NULLS="ON"
ANSI_NULL_DEFAULT="ON"
ANSI_PADDING="ON"
QUOTED_IDENTIFIER="ON"
ENCRYPTED="FALSE" />
<CommandText>CREATE TABLE [Person].[Address](
[AddressID] [int]
IDENTITY (1, 1)
NOT FOR REPLICATION NOT NULL,
[AddressLine1] [nvarchar](60) NOT NULL,
[AddressLine2] [nvarchar](60) NULL,
[City] [nvarchar](30) NOT NULL,
[StateProvinceID] [int] NOT NULL,
[PostalCode] [nvarchar](15) NOT NULL,
[rowguid] uniqueidentifier ROWGUIDCOL NOT NULL CONSTRAINT
[DF_Address_rowguid] DEFAULT (NEWID()),
[ModifiedDate] [datetime] NOT NULL CONSTRAINT
[DF_Address_ModifiedDate] DEFAULT (GETDATE())
) ON [PRIMARY];</CommandText>
</TSQLCommand>
</EVENT_INSTANCE>



 



Como podemos ver, la información presentada es bastante útil e importante, aunque en lo personal me gustaría que cuando realizaras una operación de modificación o de eliminación de un objeto, guardara un copia de la definición anterior. Para aquellos que crear valido recurrir a las Vistas de Sistema y buscar la definición les comento ya lo intente y desafortunadamente el trigger se ejecuta posteriormente al evento de tal forma que la definición de los objetos ya ha cambiado en las vistas de sistema.



 



Bien a continuación pongo un ejemplo propio del trigger que he implementado y que de momento me funciona correctamente, seguramente podrán mejorarlo y adaptarlo a sus necesidades así que ojala lo podamos comentar.



 



/**

* Trigger DDL para auditoria de cambios en el schema de las bd


* Version 1, Alamacena el detalle de los cambios en el schema de


*            las bd, evita que se borren tablas.


* 12 de Abril de 2010.


* I.S.C. Juan Carlos Armenta Bautista


**/


GO



IF  EXISTS (SELECT * FROM sys.triggers WHERE parent_class_desc = 'DATABASE' AND name = N'tr_chge_log_Db')

BEGIN


    DISABLE TRIGGER [tr_chge_log_Db] ON DATABASE;


    SELECT '[tr_chge_log_Db] Deshabilitado.....' AS msg;


END


GO



/****** Object:  DdlTrigger [tr_chge_log_Db]    Script Date: 04/12/2010 14:45:55 ******/

IF  EXISTS (SELECT * FROM sys.triggers WHERE parent_class_desc = 'DATABASE' AND name = N'tr_chge_log_Db')


BEGIN


    DROP TRIGGER [tr_chge_log_Db] ON DATABASE


    SELECT '[tr_chge_log_Db] Borrado.....' AS msg;


END


GO



create TRIGGER tr_chge_log_Db

ON DATABASE


FOR CREATE_TABLE, ALTER_TABLE, DROP_TABLE


    ,CREATE_VIEW, ALTER_VIEW, DROP_VIEW


    ,CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE


    ,CREATE_FUNCTION, ALTER_FUNCTION, DROP_FUNCTION


    ,CREATE_TRIGGER, ALTER_TRIGGER, DROP_TRIGGER


    ,CREATE_INDEX, ALTER_INDEX, DROP_INDEX


AS


BEGIN


    SET NOCOUNT ON;


    SET ARITHABORT ON;



BEGIN TRY

    DECLARE @evento as XML;


    SET @evento=EVENTDATA();


    INSERT INTO msdb.dbo.change_db_sch_log(sch_obj,nom_bd,tip_evt,nom_obj,tip_obj,tsql_cmd,nom_login)


    SELECT @evento.value('(/EVENT_INSTANCE/SchemaName)[1]','varchar(256)'),


           @evento.value('(/EVENT_INSTANCE/DatabaseName)[1]','varchar(256)'),


           @evento.value('(/EVENT_INSTANCE/EventType)[1]','varchar(50)'),


           @evento.value('(/EVENT_INSTANCE/ObjectName)[1]','varchar(256)'),


           @evento.value('(/EVENT_INSTANCE/ObjectType)[1]','varchar(25)'),


           @evento.value('(/EVENT_INSTANCE/TSQLCommand)[1]','varchar(max)'),


           @evento.value('(/EVENT_INSTANCE/LoginName)[1]','varchar(256)')


    -- Validacion del tipo de evento, si es un drop_table, se anula la operacion


    IF @evento.value('(/EVENT_INSTANCE/EventType)[1]','varchar(50)')='DROP_TABLE'


    BEGIN


        RAISERROR ('No se permite la eliminacion de tablas en la BD.',16,1);


        ROLLBACK;


    END


END TRY


BEGIN CATCH


    DECLARE @ErrorMessage NVARCHAR(4000);


    DECLARE @ErrorSeverity INT;


    DECLARE @ErrorState INT;



    SELECT  @ErrorMessage = ERROR_MESSAGE(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE();



    RAISERROR (@ErrorMessage,@ErrorSeverity,@ErrorState);

    ROLLBACK;


END CATCH   
END


GO



SELECT '[tr_chge_log_Db] Creado.....' AS msg;





 



Notas finales.



Como verán para poder borrar o modificar el trigger primero es necesario deshabilitarlo. Asi pues 2 instrucciones que seguro les serviran mucho son:



 



ENABLE TRIGGER tg_name ON DATABASE;



 



DISABLE TRIGGER tg_name ON DATABASE;



 



que creo no requieren mayor explicación.



 



Sale pues hasta aquí no más, ojala que les sea de utilidad mi primer post.



 



k@rloz.@rb@