none
Como usar método delegate em ASP.Net com C# RRS feed

  • Pergunta

  • Pessoal,

    Venho do ASP e estou migrando para ASP.Net e ainda tenho algumas dúvidas. 

    Minha dúvida atual é sobre o uso do “delegate”.

    Programo em camadas e minhas camadas atuais são:

    - UI
    - DTO
    - Business
    - DAO

    Até ai eu programei tranqüilo. Pois na DAO eu finalizo o SQL e executo o comando na base. E a minha questão é justamente neste ponto.

    Quanto eu programava em ASP, eu tinha uma função onde eu passava meu objConn e o SQL e que ficava num arquivo “include”. Assim eu não precisava ficar repetindo para tudo quanto é lado os comandos para execução no banco: create object, open, execute e close. Era o que eu chamava de “minha persistência”.

    E é isso que eu agora quero fazer no ASP.Net. Criar uma camada de persistência, onde eu digo em qual banco vou executar o comando (stringConnection) e qual o comando a ser executado (stringSQL).

    No ASP eu usava a concatenação do comando SQL (tratando adequadamente a “injeção de SQL”).  Eu passava o SQL para a função e pronto.
    Ex.: “SELECT * FROM ESTADOS WHERE NOME=’” & trataInjSQL(vNome) & “’”

    No ASP.Net eu estou trabalhando com parâmetros na string do SQL. 
    Ex.: “SELECT * FROM ESTADOS WHERE NOME=@NOME”.

    Então eu preciso adicionar os parâmetros/valores no objeto command e só depois posso executar. 

    No meu código abaixo, eu tenho o método ExecuteNonQuery, e este eu preciso refatorar transferindo-o para a camada de persistência. Porém este método precisa ser genérico e desta forma a chamada ao método adicionaParameter, precisa ser modificada, acredito eu, já que o método adicionaParameter, precisa ficar na DAO. Disseram-me que posso fazer isso com “delegate”. A questão é: como?

    Abaixo o meu código na DAO:
    + using ...
    
    namespace DAO
    {
        public class PaisesDAO
        {
            private string StrConn;
            private StringBuilder Sql;
            private MySqlParameter param = null;
    
            public PaisesDAO() { StrConn = ConnectionString.MySqlModelo; }
    
            public void insertRegistro(PaisesDTO paises)
            {
                montaSqlInsertRegistro();
                ExecuteNonQuery(Sql.ToString(), paises); 
            }
    
            private void montaSqlInsertRegistro()
            {
                Sql = new StringBuilder();
                Sql.Append("INSERT INTO PAISES (NOME) ");
                Sql.Append("VALUES (?NOME) ");
            }
    
            private void adicionaParameter(MySqlCommand cmd, PaisesDTO dto)
            {
                param = cmd.CreateParameter();
                param.ParameterName = "?NOME";
                param.Value = dto.Pai_Nome;
            }
    
            private void ExecuteNonQuery(string sql, PaisesDTO dto)
            {
                MySqlConnection con = new MySqlConnection(StrDsn);
                MySqlCommand cmd = new MySqlCommand(sql, con);
                cmd.CommandType = CommandType.Text;
    
                adicionaParameter(cmd, dto);
    
                try
                {
                    con.Open();
                    cmd.ExecuteNonQuery();
                    con.Close();
                }
                catch (Exception ex) { throw ex; }
                finally { cmd.Dispose(); con.Dispose(); }
            }
        }
    }
    

    E ai? Alguém sabe como implementar essa minha idéia usando "delegate". Pode me ajudar?

    Valeu!
    segunda-feira, 29 de março de 2010 05:21

Respostas

  • Olá Paulo,

    Não acredito que seja necessário utilizar um delegate na sua DAO para resolver o seu problema, é muito mais uma questão de arquitetura, você precisa desacoplar mais a sua DAO, o ExecuteNonQuery esta muito dependente da adicionaParameter, que esta muito dependente dos objetos da DAO. Mesmo que você utilizasse um delegate, ele estaria dependente das variáveis no contexto da DAO o que seria outro problema.

    Minha sugestão é tornar parte da sua DAO gerérica, tendo assim realmente uma camada de persistência e deixando a ExecuteNonQuery menos dependente da lógica de negócio de cada DAO. veja um exemplo abaixo de como poderia ficar a sua GenericDao.

    public abstract class GerericDao<T> where T : class
        {
            public MySqlConnection con;
            public abstract void adicionaParameter(MySqlCommand cmd, T dto);//Caso toda DAO deva ter um adicionaParameter, esse método deverá ser implementado
    
            public void ExecuteNonQuery(MySqlCommand cmd)//Aqui veja que esta totalmente desacoplado
            {
                try
                {
                    con.Open();
                    cmd.ExecuteNonQuery();
                    con.Close();
                }
                finally
                {
                    cmd.Dispose();
                    con.Dispose();
                }
            }
        }

    Assim, a sua antiga DAO ficaria dessa forma.

    public class PaisesDAO : GerericDao<PaisesDTO>
        {
            private string StrConn;
    
            public PaisesDAO()
            {
                StrConn = ConnectionString.MySqlModelo;
                base.con = new MySqlConnection(StrConn);
            }
    
            public void insertRegistro(PaisesDTO paises)
            {
                MySqlCommand cmd = new MySqlCommand(this.montaSqlInsertRegistro(paises), this.con);
                cmd.CommandType = CommandType.Text
                this.adicionaParameter(cmd,paises);
    
                base.ExecuteNonQuery(cmd);
            }
    
            private string montaSqlInsertRegistro(PaisesDTO dto)
            {
                StringBuilder Sql = new StringBuilder();
                Sql.Append("INSERT INTO PAISES (NOME) ");
                Sql.Append("VALUES (?NOME) ");
                return Sql.ToString();
            }
    
            public override void adicionaParameter(MySqlCommand cmd, PaisesDTO dto)
            {
                SqlParameter param = cmd.CreateParameter();
                param.ParameterName = "?NOME";
                param.Value = dto.Pai_Nome;
                cmd.Parameters.Add(param);
            }
        }

    Acredito que assim resolveria o seu problema com a questão do acoplamento no ExecuteNonQuery. Agora fica por sua conta ir implementando a sua GenericDao com outros métodos que sejam independentes.

    Veja se funciona e se é isso mesmo que você precisa.


    Tornar o simples complicado é facil, tornar o complicado simples é criatividade, vontade e conhecimento
    • Sugerido como Resposta AndreAlvesLimaModerator terça-feira, 30 de março de 2010 16:44
    • Marcado como Resposta PauloMau terça-feira, 30 de março de 2010 21:35
    segunda-feira, 29 de março de 2010 14:07
  • Amigo, a solução do Lázaro atinge diretamente o problema.

    Vou postar aqui alguns conceitos de padrões de projeto, se usado junto com os conceitos que o Lázaro passou, será de grande ajuda

    OBJETIVO:
    - Criar uma classe de persistência de banco de dados generica o suficiente para trabalhar com varios bancos: access , sql server...
    - Criar uma classe que sirva de template para diversas ocasiões

    Neste exemplo usaremos o banco SQL Server

    CLASSES:

    StrategyDAL:  Classe abstrata com interfaces ADO.Net
    StrategySQL:  Classe concreta com definições provider SQL Server
    StrategyContext: Classe que define qual banco será utilizado
    TemplateDAL: Classe de template com operações CRUD. Neste exemplo somente temos o método Inserir


    CLASSE ABSTRATA DE ESTRATÉGIA
    Public MustInherit Class StrategyDAL

        Public MustOverride Function Connection() As IDbConnection
        Public MustOverride Function DataAdapter(ByVal command As IDbCommand) As IDbDataAdapter
        Public MustOverride Function Command(ByVal cn As IDbConnection, ByVal sql As String, ByVal cmdtype As CommandType) As IDbCommand
        Public MustOverride Function Parameter(ByVal parameterName As String, ByVal value As Object) As IDbDataParameter

    End Class


    CLASSE CONCRETA DE ESTRATÉGIA
    Public Class StrategySQL
        Inherits StrategyDAL

        Overrides Function Connection() As IDbConnection
            Dim conexao As New SqlConnection(System.Configuration.ConfigurationManager.AppSettings("conexaostring"))
            Return conexao
        End Function

        Overrides Function DataAdapter(ByVal command As IDbCommand) As IDbDataAdapter
            Dim data_adapter As New SqlDataAdapter
            data_adapter.SelectCommand = command
            Return data_adapter
        End Function

        Overrides Function Command(ByVal cn As IDbConnection, ByVal sql As String, ByVal cmdtype As CommandType) As IDbCommand
            Dim comando As New SqlCommand
            comando.Connection = cn
            comando.CommandType = cmdtype
            comando.CommandText = sql
            Return comando
        End Function

        Overrides Function Parameter(ByVal parameterName As String, ByVal value As Object) As IDbDataParameter
            Dim parametro As New SqlParameter
            parametro.ParameterName = parameterName
            parametro.Value = value
            Return parametro
        End Function

    End Class

    CLASSE STRATEGYCONTEXT, DEFININDO A UTILIZAÇÃO DO BANCO SQL SERVER

    Public Class StrategyContext

        Private conexao As New StrategySQL
        Public Function getConfig() As StrategySQL
            Return conexao
        End Function

    End Class


    CLASSE TEMPLATE COM OPERAÇÕES CRUD
    Public MustInherit Class TemplateDAL


        Protected strategy As New StrategyContext
        Protected cn As IDbConnection
        Protected dt As SqlDataAdapter
        Protected cmd As IDbCommand


        'ASSINATURAS DA FUNÇÃO INSERIR
        Protected MustOverride Function inserirDAL(ByVal valor As Object) 

        Public Function Inserir(ByVal valor As Object) 
            Dim retorno As New DataTable
            Try
                'ABRINDO CONEXAO
                cn = strategy.getConfig.Connection()

            Catch ex As Exception
                Throw New Exception("Erro no acesso ao banco de dados: " + Err.Description)
          Finaly
               cn.Dispose()
           End Try

        End Function


    End Class

     

    IMPLEMENTAÇÃO DA CLASSE PAISESDAL UTILIZANDO O TEMPLATE DAL

    Public Class PaisesDAL
        Inherits TemplateDAL

        Protected Overrides Function inserirDAL(ByVal PaisesMOD As Object)

             Try
                cmd.Parameters.Add(dados.getCodigo) 'ADICIONANDO PARAMETROS NO COMMAND
                dt.SelectCommand = cmd                    'SETANDO DATA ADAPTER

                 cmd.ExecuteNonQuery()

              Catch ex As Exception
                     Throw New Exception("DAL: Erro ao inserir registro")           

              End Try

        End Function

    End Class

    Este foi um exemplo em VB que eu ja tinha aqui em um projeto, porém se vc reescreve-lo em C# e ainda torná-lo genêrico poderá usá-lo legal em seu projetos
    []s

     

    www.devtrainer.com.br
     


    André Rocha Agostinho
    • Sugerido como Resposta AndreAlvesLimaModerator terça-feira, 30 de março de 2010 16:44
    • Marcado como Resposta PauloMau quarta-feira, 31 de março de 2010 03:22
    segunda-feira, 29 de março de 2010 18:29

Todas as Respostas

  • Olá Paulo,

    Não acredito que seja necessário utilizar um delegate na sua DAO para resolver o seu problema, é muito mais uma questão de arquitetura, você precisa desacoplar mais a sua DAO, o ExecuteNonQuery esta muito dependente da adicionaParameter, que esta muito dependente dos objetos da DAO. Mesmo que você utilizasse um delegate, ele estaria dependente das variáveis no contexto da DAO o que seria outro problema.

    Minha sugestão é tornar parte da sua DAO gerérica, tendo assim realmente uma camada de persistência e deixando a ExecuteNonQuery menos dependente da lógica de negócio de cada DAO. veja um exemplo abaixo de como poderia ficar a sua GenericDao.

    public abstract class GerericDao<T> where T : class
        {
            public MySqlConnection con;
            public abstract void adicionaParameter(MySqlCommand cmd, T dto);//Caso toda DAO deva ter um adicionaParameter, esse método deverá ser implementado
    
            public void ExecuteNonQuery(MySqlCommand cmd)//Aqui veja que esta totalmente desacoplado
            {
                try
                {
                    con.Open();
                    cmd.ExecuteNonQuery();
                    con.Close();
                }
                finally
                {
                    cmd.Dispose();
                    con.Dispose();
                }
            }
        }

    Assim, a sua antiga DAO ficaria dessa forma.

    public class PaisesDAO : GerericDao<PaisesDTO>
        {
            private string StrConn;
    
            public PaisesDAO()
            {
                StrConn = ConnectionString.MySqlModelo;
                base.con = new MySqlConnection(StrConn);
            }
    
            public void insertRegistro(PaisesDTO paises)
            {
                MySqlCommand cmd = new MySqlCommand(this.montaSqlInsertRegistro(paises), this.con);
                cmd.CommandType = CommandType.Text
                this.adicionaParameter(cmd,paises);
    
                base.ExecuteNonQuery(cmd);
            }
    
            private string montaSqlInsertRegistro(PaisesDTO dto)
            {
                StringBuilder Sql = new StringBuilder();
                Sql.Append("INSERT INTO PAISES (NOME) ");
                Sql.Append("VALUES (?NOME) ");
                return Sql.ToString();
            }
    
            public override void adicionaParameter(MySqlCommand cmd, PaisesDTO dto)
            {
                SqlParameter param = cmd.CreateParameter();
                param.ParameterName = "?NOME";
                param.Value = dto.Pai_Nome;
                cmd.Parameters.Add(param);
            }
        }

    Acredito que assim resolveria o seu problema com a questão do acoplamento no ExecuteNonQuery. Agora fica por sua conta ir implementando a sua GenericDao com outros métodos que sejam independentes.

    Veja se funciona e se é isso mesmo que você precisa.


    Tornar o simples complicado é facil, tornar o complicado simples é criatividade, vontade e conhecimento
    • Sugerido como Resposta AndreAlvesLimaModerator terça-feira, 30 de março de 2010 16:44
    • Marcado como Resposta PauloMau terça-feira, 30 de março de 2010 21:35
    segunda-feira, 29 de março de 2010 14:07
  • Amigo, a solução do Lázaro atinge diretamente o problema.

    Vou postar aqui alguns conceitos de padrões de projeto, se usado junto com os conceitos que o Lázaro passou, será de grande ajuda

    OBJETIVO:
    - Criar uma classe de persistência de banco de dados generica o suficiente para trabalhar com varios bancos: access , sql server...
    - Criar uma classe que sirva de template para diversas ocasiões

    Neste exemplo usaremos o banco SQL Server

    CLASSES:

    StrategyDAL:  Classe abstrata com interfaces ADO.Net
    StrategySQL:  Classe concreta com definições provider SQL Server
    StrategyContext: Classe que define qual banco será utilizado
    TemplateDAL: Classe de template com operações CRUD. Neste exemplo somente temos o método Inserir


    CLASSE ABSTRATA DE ESTRATÉGIA
    Public MustInherit Class StrategyDAL

        Public MustOverride Function Connection() As IDbConnection
        Public MustOverride Function DataAdapter(ByVal command As IDbCommand) As IDbDataAdapter
        Public MustOverride Function Command(ByVal cn As IDbConnection, ByVal sql As String, ByVal cmdtype As CommandType) As IDbCommand
        Public MustOverride Function Parameter(ByVal parameterName As String, ByVal value As Object) As IDbDataParameter

    End Class


    CLASSE CONCRETA DE ESTRATÉGIA
    Public Class StrategySQL
        Inherits StrategyDAL

        Overrides Function Connection() As IDbConnection
            Dim conexao As New SqlConnection(System.Configuration.ConfigurationManager.AppSettings("conexaostring"))
            Return conexao
        End Function

        Overrides Function DataAdapter(ByVal command As IDbCommand) As IDbDataAdapter
            Dim data_adapter As New SqlDataAdapter
            data_adapter.SelectCommand = command
            Return data_adapter
        End Function

        Overrides Function Command(ByVal cn As IDbConnection, ByVal sql As String, ByVal cmdtype As CommandType) As IDbCommand
            Dim comando As New SqlCommand
            comando.Connection = cn
            comando.CommandType = cmdtype
            comando.CommandText = sql
            Return comando
        End Function

        Overrides Function Parameter(ByVal parameterName As String, ByVal value As Object) As IDbDataParameter
            Dim parametro As New SqlParameter
            parametro.ParameterName = parameterName
            parametro.Value = value
            Return parametro
        End Function

    End Class

    CLASSE STRATEGYCONTEXT, DEFININDO A UTILIZAÇÃO DO BANCO SQL SERVER

    Public Class StrategyContext

        Private conexao As New StrategySQL
        Public Function getConfig() As StrategySQL
            Return conexao
        End Function

    End Class


    CLASSE TEMPLATE COM OPERAÇÕES CRUD
    Public MustInherit Class TemplateDAL


        Protected strategy As New StrategyContext
        Protected cn As IDbConnection
        Protected dt As SqlDataAdapter
        Protected cmd As IDbCommand


        'ASSINATURAS DA FUNÇÃO INSERIR
        Protected MustOverride Function inserirDAL(ByVal valor As Object) 

        Public Function Inserir(ByVal valor As Object) 
            Dim retorno As New DataTable
            Try
                'ABRINDO CONEXAO
                cn = strategy.getConfig.Connection()

            Catch ex As Exception
                Throw New Exception("Erro no acesso ao banco de dados: " + Err.Description)
          Finaly
               cn.Dispose()
           End Try

        End Function


    End Class

     

    IMPLEMENTAÇÃO DA CLASSE PAISESDAL UTILIZANDO O TEMPLATE DAL

    Public Class PaisesDAL
        Inherits TemplateDAL

        Protected Overrides Function inserirDAL(ByVal PaisesMOD As Object)

             Try
                cmd.Parameters.Add(dados.getCodigo) 'ADICIONANDO PARAMETROS NO COMMAND
                dt.SelectCommand = cmd                    'SETANDO DATA ADAPTER

                 cmd.ExecuteNonQuery()

              Catch ex As Exception
                     Throw New Exception("DAL: Erro ao inserir registro")           

              End Try

        End Function

    End Class

    Este foi um exemplo em VB que eu ja tinha aqui em um projeto, porém se vc reescreve-lo em C# e ainda torná-lo genêrico poderá usá-lo legal em seu projetos
    []s

     

    www.devtrainer.com.br
     


    André Rocha Agostinho
    • Sugerido como Resposta AndreAlvesLimaModerator terça-feira, 30 de março de 2010 16:44
    • Marcado como Resposta PauloMau quarta-feira, 31 de março de 2010 03:22
    segunda-feira, 29 de março de 2010 18:29
  • Lazaro: 

    Gostei dessa solução. Já apliquei e funcionou 100%. O que é óbvio, considerando sua experiência.

    ---------
    Enquanto no ASP eu cheguei a dar aula de ASP no infnet.edu.br (2000-2005)... Sou um novato total no ASP.Net, pois não acompanhei a tendência na época (início de 2000) e agora tô eu aqui, com diversas dúvidas... 

    Na verdade eu até que dei muita sorte, pq no único projeto que trabalhei até agora, foi com um camarada super 100%... Rinaldo Benevides.

    Ele tinha uma camada própria de persistência... Só que é muito para minha cabeça... :) Pelo menos, por enquanto. Então estou meio que tentando fazer a organização em camadas que aprendi com ele, mas fazendo minha camada de persistência meio que parecida com o que eu fazia no ASP. Lógico que agora... Fazendo o possível para aprender e utilizar OO, bem como o .Net.
    ---------

    Então... Nessa nova classe PaisesDAO, eu continuo tendo que instanciar o objeto cmd. Eu queria abstrair mais. 

    Mas valeu! Tua solução já atende meu início. Agora é aprender mais e depois é só refatorar. :)

    Bom... Nesse caso, estou lendo, relendo e relendo o que o André Rocha escreveu... :) Já vi que vocês devem trabalhar juntos.

    Até!

    terça-feira, 30 de março de 2010 23:15
  • Em tempo:

    As respostas recebidas atenderam as minhas necessidades e neste caso, minha pergunta sobre o uso dos delegates não condiz com o que eu realmente precisava.

    Voltarei aos delegates em tempo oportuno. Grato!

    terça-feira, 30 de março de 2010 23:32
  • Oi André,

    Quero agradecer a sua resposta também.

    Na verdade o que mais quero é criar minha camada de persistência da forma que você falou em "objetivo". Mas como pode ler na resposta que escrevi para o Lazaro, sou bem novato, porém querendo e tentando fazer a coisa mais certa possível, utilizando meu conhecimento e buscando com quem sabe.

    Que bom que decidi postar aqui e encontrei vocês, que me responderam.

    É muita coisa para assimilar... Incluindo os padrões a que se referiu. Eu até tenho o livro "Padrões de Porjeto" (ed.: bookman; por e.gamma, r.helm, r.johnson e j.vlissides). Já iniciei a leitura, mas a assimilação está acontecendo aos poucos. :)

    Vou reler o padrão strategy (pág.292 do livro) e voltar a reler o código que você sugeriu aqui. 

    Bom. Gostaria de discutir o meu projeto modelo... Na verdade, as camadas que estou utilizando no mesmo. Da UI a Persistence. Mas fica pra uma nova pergunta para não misturar os assuntos, e espero que tenha a oportunidade de ler e dar sua opinião. 

    Grato pela atenção de todos que leram e puderam ajudar... 

    Grato Lázaro. Grato André.

    terça-feira, 30 de março de 2010 23:54
  • Olá Paulo!

    Fico agradecido pelos elogios e principalmente por ter lhe ajudado a desenvolver os seus conhecimentos.

    Acredito que o ritmo é esse mesmo, aprendizado aos poucos, realmente leva um tempo para assimilar, é necessário ir pegando experiência.

    Caso precise abstrair mais seu modelo, é possível sim, porém, eu não queria aprofundar muito na refatoração naquele código que você postou, quiz somente manter a sua idéia inicial sem uma mudança radical, resolvendo aquele problemas esperífico na ExecuteNonQuery, por isso seu código ainda não esta 100% na parte da montagem do command, mais ai é outro assunto, poste um novo tópico para aprodundarmos as discussões.

    ate mais, abraços


    Tornar o simples complicado é facil, tornar o complicado simples é criatividade, vontade e conhecimento
    quarta-feira, 31 de março de 2010 13:45