Select columns dynamically with Linq

0

I have an action in an API that should return a template, however the fields that must be returned are entered in the request. I can query with the System.Linq.Dynamic.Core package, but the performance is pretty bad. What other alternative can I use? I'm using .Net 4.5

Query example:

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}";
}
    
asked by anonymous 09.10.2018 / 18:50

2 answers

0

I'll follow the user's "LINQ" tip, thanks man. OData is the best option in my case. I'm implementing a restful API, following all good practices, so this is the best option. Because when creating an odata controller in the api, with the default actions that Visual Studio creates, I can already have an action that does exactly what I need, receive a request with the desired fields and return those fields in json, automatic, no need to do anything. And the performance is as good as a regular linq query.

A link for an OData implementation article in .Net Core.

Example odata url:

  

link ? $ select = Id, Name

Action example:

//Essa action responde a url acima
[EnableQuery]
public IQueryable<Profissional> GetProfissional()
{
    return db.Profissional;
}
    
11.10.2018 / 00:24
2

Using the dynamic type, the ExpandoObject class that supports IDictionary<string, object> to add the properties at run time ... 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;
        }          

    }

}

Demo:

Reference:

Building C # objects dynamically - O'Reilly Media

    
10.10.2018 / 03:25