Filter Postgresql Information on Windows Forms screen using Entity Framework

Asked

Viewed 230 times

6

Is there any way to search for the information in postgresql by nickname? But without using alias, only in the field register in the table I already enter the real name for the field?

Example:

  1. id_client will be named "Client Code"
  2. dtNascimento as the name of "Date of Birth"

Because I would like to create a generic class that works for any table, thus putting the field name as a filter. Something like:

inserir a descrição da imagem aqui

Where the field for the filter will be the table field with the real name.

That so each field added in the table in the future can already be used as a filter in a search screen and already with the real name for the user.

Is there any way to do that? I just need some hint of what research the code will turn me around, but I don’t know what technology to use or where to start.

  • 1

    A somewhat unrelated question: are you using ASP.NET or is it a desktop application? If it’s desktop, it’s Winforms or WPF?

  • Desktop using WPF but can be applied with Winforms too, I’m still testing.

  • This is actually indifferent. Basically what you have to do is the following: Create an attribute (attribute) customized to be able to define the name (readable, visualization) of each property and then when mounting the screen search these names and fill the ComboBox. The real name of the property will be the real value of the Combo and the name defined by attribute will be the display name on Combo (DisplayName). You can do it quietly with Reflection.

  • @jbueno understood, but so I will have to implement in each search screen the values. If I use according to the response of the Gypsy, I can only by changing the entity and moving the migration to base, already show on the search screen for the user

  • 1

    Of the two: either I did not understand what you want to do or you did not understand the reply of the Gypsy.

  • So @jbueno I didn’t want to put on my screen the value of each attribute, I wanted to already pull from the entity the real value of the Collumn attribute. Because then no matter the screen I implement, I just pass a list of the columns and the user assembles his search, same as the initial image of the question. The reason for this is to be able to create a generic class to do an advanced search on any entity.

  • It’s basically what I said in the comment above, @apprentice

Show 2 more comments

1 answer

4


Yes. Use [Column]:

[Column("Código Cliente")]
public int ClienteId { get; set; }

[Column("Data de Nascimento")]
public DateTime DataNascimento { get; set; }

The question title should be "how to filter in Winforms by the name of the displayed column". I did a simulation and then I must edit this answer and put the example in a chapter of Coding Craft because I unintentionally made a tutorial on how to use Entity Framework with Windows Forms and Postgresql.

Let’s go to the questions:

Is there any way to search the information in postgresql by nickname? but without using alias, only in the field registration in the table I already inform the real name for the field?

No. You need to pass the name of the column yourself. What you can do is the user interface display the friendly column name and the code receive the column name as it is in fact.

Because I would like to create a generic class that works for any table, thus putting the field name as a filter.

That involves using a lot Reflection. Using the "field name" is not a good idea, but you can display the field name and get another value.

To illustrate, I will make a full example.

Model and Tela

I modeled a class Cliente as an example:

public class Cliente
{
    [Key]
    [DisplayName("Identificador do Cliente")]
    public Guid ClienteId { get; set; }

    [Required]
    [DisplayName("Nome do Cliente")]
    public String Nome { get; set; }
    [Required]
    [DisplayName("Nome Fantasia")]
    public String Fantasia { get; set; }
}

That is, each property of the class of Cliente has an attribute [DisplayName]. This attribute will be what I will display to the user.

Once done, I can make the following code to popular the compo "Search Fields":

        var camposPesquisa = typeof(Cliente).GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
                           BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
                           .Select(p => new {
                               Valor = p.Name,
                               Texto = p.GetCustomAttribute<DisplayNameAttribute>().DisplayName
                           }).ToList();

        comboBoxCampoPesquisa.ValueMember = "Valor";
        comboBoxCampoPesquisa.DisplayMember = "Texto";
        comboBoxCampoPesquisa.DataSource = camposPesquisa;

That is, my screen will display the values of [DisplayName], but the values that will go into the code are the names of my fields:

Exemplo de Combo de Campo para Pesquisa

I can do the same thing for the condition by defining a Enum Condicao and put attributes [Display] in them:

public enum Condicao
{
    [Display(Name = "Igual")]
    Igual,
    [Display(Name = "Diferente")]
    Diferente,
    [Display(Name = "Maior")]
    Maior,
    [Display(Name = "Menor")]
    Menor,
    [Display(Name = "Maior ou Igual")]
    MaiorOuIgual,
    [Display(Name = "Menor ou Igual")]
    MenorOuIgual
}

To extract the attribute of Enums, you will need an extension method:

public static class EnumExtensions
{
    public static TAttribute GetAttribute<TAttribute>(this Enum enumValue)
            where TAttribute : Attribute
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<TAttribute>();
    }
}

To use it like this:

        var condicoes = Enum.GetValues(typeof(Condicao))
            .Cast<Condicao>()
            .Select(c => new
            {
                Valor = c.ToString(),
                Texto = c.GetAttribute<DisplayAttribute>().Name
            })
            .ToList();

        comboBoxCondicao.ValueMember = "Valor";
        comboBoxCondicao.DisplayMember = "Texto";
        comboBoxCondicao.DataSource = condicoes;

And then:

Exemplo de Combo para Condição

Grid

I’m guessing the initialization of the Grid is made in the event OnLoad of your Form

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        context.Clientes.Load();

        clienteBindingSource.DataSource =
            context.Clientes.Local.ToBindingList();

        ...
    }

Only with this I have the research of the data and the proper observation by them through the context of the Entity Framework. Done this, I need to put a CheckBox and an event for it to trigger the filtering at the appropriate time:

    private void checkBoxFiltrar_CheckedChanged(object sender, EventArgs e)
    {
        Filtrar(checkBoxFiltrar.Checked);
    }

Just as a test, I filtered by name as follows:

    protected void Filtrar(bool checkFiltrar)
    {
        if (checkFiltrar)
            clienteBindingSource.DataSource = context.Clientes.Where(c => c.Nome == textBoxValor.Text).ToList();
        else
            clienteBindingSource.DataSource = context.Clientes.Local.ToBindingList();

        dataGridView.Refresh();
    }

Here is the starting point for a more robust logic. There are two ways to do it: using the library System.Linq.Dynamic or riding Expressions. For this answer I will use the first (which, at bottom, does the same thing as the second).

Predicados Dinâmica

Let’s just assemble the dynamic predicate for Condicao.Igual:

    protected void Filtrar(bool checkFiltrar)
    {
        if (checkFiltrar)
            // clienteBindingSource.DataSource = context.Clientes.Where(c => c.Nome == textBoxValor.Text).ToList();
            clienteBindingSource.DataSource = context.Clientes
                .Where(comboBoxCampoPesquisa.SelectedValue.ToString() + " == @0", textBoxValor.Text)
                .ToList();
        else
            clienteBindingSource.DataSource = context.Clientes.Local.ToBindingList();

        dataGridView.Refresh();
    }

Checking whether it works:

Filtrando

Finally, as I want to search not for the exact text, but for a part of it, I can do the following:

    protected void Filtrar(bool checkFiltrar)
    {
        if (checkFiltrar)
            // clienteBindingSource.DataSource = context.Clientes.Where(c => c.Nome == textBoxValor.Text).ToList();
            clienteBindingSource.DataSource = context.Clientes
                // .Where(comboBoxCampoPesquisa.SelectedValue.ToString() + " == @0", textBoxValor.Text)
                .Where(comboBoxCampoPesquisa.SelectedValue.ToString() + ".Contains(@0)", textBoxValor.Text)
                .ToList();
        else
            clienteBindingSource.DataSource = context.Clientes.Local.ToBindingList();

        dataGridView.Refresh();
    }

Convert the Enum to an operator String is like homework.

  • Okay Thanks, but how could I do the search or return of SQL via collumn Entity? I was left with doubt in this part

  • 1

    Ah, you want to create multiple entities with customer code and date of birth? Which entities would be?

  • Example: User entity, I have the fields ( id_user, login, dtCreation, situation). I want to play these fields for combobox but already using Collum passing his real name.

  • 2

    Ah, @Ciganomorrisonmendez He wants to put in a combo the nickname (as value for visualization) and also the real name of the property (as real value). To make it possible to make a filter using the selected value in ComboBox

  • 1

    Ah, so the question is about doing a database search using the HeaderText column. But what is the use of it? It is not better to use Name?

  • @jbueno exactly what I want to do.

  • @Apprentice How are you mounting your research today?

  • @I’m a beginner, but I’m trying to create in a way that I’m not quite sure how to start, but that would be about it: // T sera minha entidadade .. usuario ou cliente &#xA; public abstract class BuscaAvancada<T> where T : class&#xA; {&#xA; // retornar uma lista das colunas com os apelidos. essa parte nao sei como implementar&#xA; public List<T> buscaColunas() {&#xA;&#xA; return listadeColunas();&#xA; }&#xA; }&#xA; The return of this listColunas would put in my combobox to list the fields (by nickname) in the search screen,

  • So the user mounts his search according to which field he wants to put, but I need the field to be the nickname. I don’t know if it was clear

  • 1

    Ah, I understand what you want. I’m going to need to do some simulations here. It might take a while, okay?

  • @Apprentice There it is. I hope you clarify your doubt.

  • @Gypsy omorrisonmendez give me your address and I’ll send you a box of haha beer. That’s what I really needed, man. I will try to implement it my way now by putting everything in a class and calling where I need it. Thanks for the help

  • I live in the United States, but has this link to send me a box of bad. A hug!

  • I am trying to validate which fields have no display name, but as there are no null I get Exception. But even checking the different null fields still returns the error. Where(p=> p.GetCustomAttribute<DisplayNameAttribute>().DisplayName != null).Select [ ... ]. When it arrives in the dysdysplasia I get the error.

  • Ask another question, please.

Show 10 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.