Conexão BD C# ?

8 respostas Resolvido
csharp
EduGomes

Olá mais uma vez, hoje as dúvidas estão surgindo.

Seguinte, até o momento eu estava testando meu projeto no localhost, mas então decidi colocar o banco de dados em outra máquina e acessar pela rede. E foi ai que eu notei lentidão em alguns pontos.

Essa é minha função de conexão no banco de dados:

public class ConexaoDAO
{
    protected static string Conecta = "DATABASE=nomedatabase; SERVER=192.168.0.0; UID=user; PWD=password";
    protected MySqlConnection Conexao;
    protected MySqlTransaction tr = null;
    protected MySqlCommand Comando = null;

    //MÉTODO PARA CONECTAR NO BANCO
    public void AbrirConexao()
    {
        try
        {
            Conexao = new MySqlConnection(Conecta);
            Conexao.Open();
        }
        catch (MySqlException ex)
        {
            Console.WriteLine("Error: {0}", ex.ToString());
        }
    }

    //METODO PARA FECHAR A CONEXAO COM O BANCO

    public void FecharConexao()
    {
        try
        {
            if (Conexao != null)
            {
                Conexao.Close();
            }
        }
        catch (MySqlException ex)
        {
            Console.WriteLine("Error: {0}", ex.ToString());
        }
    }
}

Então, uma das partes que está lenta é por exemplo na função que retorna uma lista com os usuários do sistema :

public List<Usuario> BuscaUsuarios(string codGrupoUsuario, string nomeUsuario, string sobrenomeUsuario)
    {

        List<Usuario> usuarios = new List<Usuario>();

        string conCodGrupoUsuario = codGrupoUsuario.Length > 0 ? "AND g.idgrupousuario = @idgrupousuario" : "";
        string conNomeUsuario = nomeUsuario.Length > 0 ? "AND u.nome LIKE @nomeusuario" : "";
        string conSobrenomeUsuario = sobrenomeUsuario.Length > 0 ? "AND u.sobrenome LIKE @sobrenomeusuario" : "";


        try
        {
            AbrirConexao();
            Comando = new MySqlCommand(@"SELECT *
                                         FROM usuario u INNER JOIN grupo_usuario g 
                                         ON u.idgrupousuario = g.idgrupousuario
                                         WHERE 1=1
                                         " + conCodGrupoUsuario + @"
                                         " + conNomeUsuario + @"
                                         " + conSobrenomeUsuario + @"
                                         ORDER BY u.idusuario;", Conexao);

            if (codGrupoUsuario.Length > 0) { Comando.Parameters.AddWithValue("@idgrupousuario", codGrupoUsuario); }
            if (nomeUsuario.Length > 0) { Comando.Parameters.AddWithValue("@nomeusuario", "%" + nomeUsuario + "%"); }
            if (sobrenomeUsuario.Length > 0) { Comando.Parameters.AddWithValue("@sobrenomeUsuario", "%" + sobrenomeUsuario + "%"); }

            IDataReader reader = Comando.ExecuteReader();

            while (reader.Read())
            {

                Usuario usuario = new Usuario
                {
                    UsuarioID = reader.GetInt32(reader.GetOrdinal("idusuario")),
                    Senha = reader.GetString(reader.GetOrdinal("senha")),

                    Grupousuario = grupousuarioBLL.BuscaGrupoUsuarioByID(reader.GetString(reader.GetOrdinal("idgrupousuario"))),

Nome = reader.GetString(reader.GetOrdinal("nome")),
                    Sobrenome = reader.GetString(reader.GetOrdinal("sobrenome")),
                    Email = reader.GetString(reader.GetOrdinal("email")),
                    Telefone = reader.GetString(reader.GetOrdinal("telefone"))
                };


                usuarios.Add(usuario);
            }
        }
        catch (MySqlException ex)
        {
            Console.WriteLine("Error: {0}", ex.ToString());
        }
        finally
        {
            FecharConexao();
        }
        return usuarios;
    }

O problema está nessa parte :

Grupousuario = grupousuarioBLL.BuscaGrupoUsuarioByID(reader.GetString(reader.GetOrdinal(“idgrupousuario”))),

Pois aqui eu chamo outra função, que busca o grupo que o usuário pertence. E nessa outra função eu chamo uma terceira função que busca e insere as permissões nesse grupo:

public GrupoUsuario BuscarGrupoUsuarioById(string cod)
{
    GrupoUsuario grupousuario = new GrupoUsuario(); ;
    try
    {

        AbrirConexao();

        Comando = new MySqlCommand("SELECT * FROM grupo_usuario WHERE idgrupousuario = @idgrupousuario", Conexao);
        Comando.Parameters.AddWithValue("@idgrupousuario", cod);

        IDataReader reader = Comando.ExecuteReader();

        if (reader.Read())
        {
            grupousuario = new GrupoUsuario
            {
                GrupoUsuarioID = int.Parse(reader.GetString(reader.GetOrdinal("idgrupousuario"))),
                Nome = reader.GetString(reader.GetOrdinal("nome")),
                Permissoes = permissaoBLL.BuscaPermissoesByIdGrupo(reader.GetString(reader.GetOrdinal("idgrupousuario"))).Todas
            };

            reader.Close();
        }
        else
        {
            grupousuario = null;
        }
    }
    catch (MySqlException ex)
    {
        Console.WriteLine("Error: {0}", ex.ToString());
    }
    finally
    {
        FecharConexao();
    }
    return grupousuario;
}

Bom, como vocês podem ver eu acabei fazendo uma função buscando outra. E cada uma dessas funções abre uma nova conexão. Estou pensando em alguma maneira de fazer isso de um jeito diferente, mas não sei certo por onde começar.
Alguma sugestão ?

Obrigado desde já

8 Respostas

T

Olá!
Olhando a sua função:

Especificamente neste ponto:

Se as suas permissões é por grupo de usuários. Minha sugestão, s.m.j., não seria o caso de unificar as tabelas grupo_usuario e permissoes, para evitar a utilização da função BuscaPermissoesByIdGrupo? Ou tem tratamento diferenciado para as permissões dos usuários?

Dragoon
Solucao aceita

Você fez herança da classe de conexão?
Se fez tem um problema de designer, que causa lentidão, que causa concorrência com o banco de dados e isso num cenário de muitas computadores acessando essa aplicação, o correto é injetar a conexão e não fazer herança, exemplo:

Classes

public class Connection {} // classe de conexão
public class DalPeople {
    public Connection Connect { get; }
    public DalPeople(Connection c) {
        Connect = c;
    }
}
public class DalCar {
    public Connection Connect { get; }
    public DalCar(Connection c) {
        Connect = c;
    }
}

Utilização:

Connection connection = new Connection();
DalPeople dalPeople = new DalPeople(connection);
DalCar dalCar = new DalCar(connection);

assim 1 conexão é compartilhada nas suas classes que precisam utilizar conexão com o banco …

Outra coisa se pode utilizar um IEnumerable<T> para listar suas informações.

EduGomes

Olá.
Na verdade eu tenho uma relação de muitos para muitos entre permissões e grupo_usuario, e nesta tabela N para N eu tenho uma coluna nível, que no caso é diferente para cada ligação. Na tabela de permissões eu tenho tanto permissões de telas, quanto de funções, e também módulos, que eu relaciono de acordo com um valor chamado código. Exemplo, Modulo 1 o código é 010000, as telas desse módulo receberiam códigos como por exemplo 010100, 010200, e assim vai. Então tenho um Struct de Permissao que contém 4 listas, uma de módulos, uma de telas, funções e uma lista com Tudo. E uso essa função para fazer a separação:

public fmCadastroGrupoUsuario.PermissoesStruct BuscaPermissoesByIdGrupo(string cod)
{

    fmCadastroGrupoUsuario.PermissoesStruct permissoes = new fmCadastroGrupoUsuario.PermissoesStruct();

    permissoes.Todas = new List<Permissao>();
    permissoes.Modulos = new List<Permissao>();
    permissoes.Telas = new List<Permissao>();
    permissoes.Funcoes = new List<Permissao>();

    try
    {
        AbrirConexao();
        Comando = new MySqlCommand(@"SELECT * 
                                     FROM permissao_has_grupo_usuario pg INNER JOIN permissao p 
                                     ON pg.idpermissao = p.idpermissao 
                                     WHERE idgrupousuario = @idgrupousuario", Conexao);
        Comando.Parameters.AddWithValue("@idgrupousuario", cod);

        IDataReader reader = Comando.ExecuteReader();

        while (reader.Read())
        {
            
            string codfiltro = reader.GetString(reader.GetOrdinal("codigo"));

            Permissao p = new Permissao
            {
                PermissaoId = reader.GetInt32(reader.GetOrdinal("idpermissao")),
                Nome = reader.GetString(reader.GetOrdinal("nome")),
                Codigo = reader.GetString(reader.GetOrdinal("codigo")),
                Nivel = reader.GetString(reader.GetOrdinal("nivel"))
            };
            permissoes.Todas.Add(p);

            if (codfiltro.Substring(2) == "0000")
            {
                permissoes.Modulos.Add(p);
            }

            if (codfiltro.Substring(4) == "00")
            {
                permissoes.Telas.Add(p);
            }

            if (codfiltro.Substring(4) != "00")
            {
                permissoes.Funcoes.Add(p);
            }

        }
        reader.Close();
    }
    catch (MySqlException ex)
    {
        Console.WriteLine("Error: {0}", ex.ToString());
    }
    finally
    {
        FecharConexao();
    }

    return permissoes;
}

Mas talvez deva unificar as tabelas nessa situação.

EduGomes

Ahh. Sim eu fiz, então isso deve ser um dos problemas. Realmente não sabia disso

Dragoon

Sim é um problema não pode fazer herança assim …
Injetar que é melhor porque uma conexão é para todas as classes que precisam …

Utilize estruturas mais leves para trazer resultados como IEnumerable<T>

EduGomes

Você teria alguma exemplo de utilização do IEnumerable ?
Li um pouco sobre agora que você indicou, mas ainda não ficou muito claro.

Dragoon

Mais ou menos assim:

Classe Modelo Teacher:

public class Teacher
{
	public int Id { get; set; }
	public string Name { get; set; }
}

Método da classe DalTeacher:

public IEnumerable<Teacher> GetAll()
{
	using (SqlCommand command = Connection.CreateCommand())                
	{
		command.CommandText = "SELECT Id, Name FROM Teacher";
		using (SqlDataReader reader = command.ExecuteReader())
		{
			while (reader.Read())
			{
				yield return new Teacher
				{
					Id = reader.GetInt32(0),
					Name = reader.GetString(1)
				};
			}
		}
	}
}

ou seja, em vez de criar um instância de uma lista pode fazer um empilhamento que chama carga atrasada no C#, e quando utilizar um ToList ele materializa. São assim que são feitos os códigos de Lista em C#, apesar que agora está vindo uns tipos melhores, mais performáticos, mas, que no momento não vem ao caso.

EduGomes

Hum. Muito interessante.
Bah muito obrigado mesmo.

Criado 12 de abril de 2019
Ultima resposta 12 de abr. de 2019
Respostas 8
Participantes 3