Usuário com melhor resposta
Como usar método delegate em ASP.Net com C#

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- DAOAté 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!
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
-
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 ajudaOBJETIVO:
- 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õesNeste 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 StrategyDALPublic 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 IDbDataParameterEnd Class
CLASSE CONCRETA DE ESTRATÉGIA
Public Class StrategySQL
Inherits StrategyDALOverrides Function Connection() As IDbConnection
Dim conexao As New SqlConnection(System.Configuration.ConfigurationManager.AppSettings("conexaostring"))
Return conexao
End FunctionOverrides Function DataAdapter(ByVal command As IDbCommand) As IDbDataAdapter
Dim data_adapter As New SqlDataAdapter
data_adapter.SelectCommand = command
Return data_adapter
End FunctionOverrides 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 FunctionOverrides 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 FunctionEnd 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 FunctionEnd 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 TryEnd Function
End ClassIMPLEMENTAÇÃO DA CLASSE PAISESDAL UTILIZANDO O TEMPLATE DAL
Public Class PaisesDAL
Inherits TemplateDALProtected 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
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
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
-
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 ajudaOBJETIVO:
- 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õesNeste 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 StrategyDALPublic 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 IDbDataParameterEnd Class
CLASSE CONCRETA DE ESTRATÉGIA
Public Class StrategySQL
Inherits StrategyDALOverrides Function Connection() As IDbConnection
Dim conexao As New SqlConnection(System.Configuration.ConfigurationManager.AppSettings("conexaostring"))
Return conexao
End FunctionOverrides Function DataAdapter(ByVal command As IDbCommand) As IDbDataAdapter
Dim data_adapter As New SqlDataAdapter
data_adapter.SelectCommand = command
Return data_adapter
End FunctionOverrides 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 FunctionOverrides 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 FunctionEnd 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 FunctionEnd 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 TryEnd Function
End ClassIMPLEMENTAÇÃO DA CLASSE PAISESDAL UTILIZANDO O TEMPLATE DAL
Public Class PaisesDAL
Inherits TemplateDALProtected 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
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
-
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é!
-
-
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é.
-
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