Select columns dynamically with Linq

Asked

Viewed 608 times

0

I have an action in an API that should return a model, but the fields that should be returned are informed in the request. I can do a query with the System.Linq.Dynamic.Core package, but the performance is really bad. What other alternative can I use? I’m using. Net 4.5

Example of consultation:

var contexto = new SgdbContext();

//Esse select só é possivel por causa do pacote
foreach(dynamic profissional in contexto.Profissional.Select("new (Id, Nome)"))
{
    var conteudo = $"{profissional.Id} - {profissional.Nome}";
}
  • 1

    Show what you already have of code.

  • The query I made is a basic select bringing 2 columns (id and name for example), but only in this test to notice the slowness. There’s no way I’m using that code.

  • Maybe you need to look for Odata. Probably, nowadays there is something better, or an improved version, but I think that’s the way.

  • I got a solution with dynamic at night I put

  • Post your action

2 answers

2

Using the type dynamic, the class ExpandoObject that supports IDictionary<string, object> to add the properties at runtime... You can start your implementation with the example below.

public class PessoasController : ApiController
{      
    public IEnumerable<object> Get(string exibir = "")
    {
        //Consulta ao repositório, simulada.
        var lista = new List<PessoaViewModel>
        {
            new PessoaViewModel{ Id = 1, Nome="Nome 1", Sobrenome = "Sobrenome 1" },
            new PessoaViewModel{ Id = 2, Nome="Nome 2", Sobrenome = "Sobrenome 2" },
            new PessoaViewModel{ Id = 3, Nome="Nome 3", Sobrenome = "Sobrenome 3" }
        };


        //faz o split pelo separador 
        var queryFilter = exibir.Split(',');

        if (string.IsNullOrWhiteSpace(exibir) && queryFilter.Length <= 0)
        {
            return lista;
        }
        else{
            // Utilizando reflection retorna apenas as propriedades informadas no filtro,
            // que existem no objeto comparação.
            var propriedades = typeof(PessoaViewModel)
                .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Where(x => queryFilter.Select(q => q.ToLower()).Contains(x.Name.ToLower()))
                .ToList();

            // Se as propriedades de filtro não batem com o modelo, retorna o objeto inteiro
            if (propriedades.Count() == 0)
                return lista;

            // Aqui é a onde a mágica acontece, utilizando o ExpandoObject,
            // criamos um dicionário armazenando o nome e valor daquelas 
            // propriedades que existem, de fato, na classe.
            var output = lista.Select(registro =>
            {
                dynamic x = new ExpandoObject();
                var temp = x as IDictionary<string, object>;

                foreach (var prop in propriedades)
                    temp.Add(prop.Name, prop.GetValue(registro));

                return x;
            });

            return output;
        }          

    }

}

Demonstration:

inserir a descrição da imagem aqui

Reference:

Building C# Objects dynamically - O'Reilly Media

  • Nice, but the ideal is that the EF already did it (ridiculous that even version 6 has nothing of the type). I tried using the context Sqlquery<Model> method, but it also doesn’t let me bring only the fields I need (dynamically)

  • Hmm, you want to make the dynamic select in EF tbm, I thought your question was more related to the return of the value in the api, so in this case the tag asp.net-web-api is irrelevant, correct?

  • Remembering that Reflection is extremely slow.

0


I will follow the tip of the user "LINQ", thanks man. O Odata is the best option in my case. I am implementing a restful api, following all good practices, so this is the best option. Because by creating a controller in the api, with the standard actions that Visual Studio creates, I can already have an action that does just what I need, receive a request with the desired fields and return these fields in the json, automatic, I don’t need to do anything. And the performance is as good as a normal query.

A link of an article implementing Odata in . Net Core.

Example of odata url:

http://localhost:51971/odata/Professional?$select=Id,Name

Example of the action:

//Essa action responde a url acima
[EnableQuery]
public IQueryable<Profissional> GetProfissional()
{
    return db.Profissional;
}
  • Showzera. When you have a basic implementation, post the code in that response.

  • Done. Ball show.

Browser other questions tagged

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