How to avoid repetition in LINQ queries?

Asked

Viewed 156 times

4

I have the following query LINQ which is in a method that returns all products:

var query = from p in Produtos
    select new Produto
    {
        ProdutoId = p.ProdutoId,
        Descricao = p.Descricao,
        Preco = p.Preco,
        Estoque = p.Estoque
    };
return query;

I also have other methods that return the same fields being filtered by certain conditions ex:

var query = from p in Produtos
    where p.Descricao.StartsWith(descricao)
    select new Produto
    {
        ProdutoId = p.ProdutoId,
        Descricao = p.Descricao,
        Preco = p.Preco,
        Estoque = p.Estoque
    };
return query;

Is there any way to avoid repeating the passage:

  select new Produto
  {
      ProdutoId = p.ProdutoId,
      Descricao = p.Descricao,
      Preco = p.Preco,
      Estoque = p.Estoque

  };

With this, if you want to add/remove some field, you wouldn’t have to change all methods.

Other solutions are also welcome.

  • Try to put inside a switch statament

  • 3

    @Eduardoalmeida I was curious, please show how it is possible to resolve this with switch.

  • I found this example in C#: http://stackoverflow.com/questions/17405348/avoiding-repeating-code-with-linq-query-optional-params I usually program in PHP (so I didn’t write in response), but the solutions can be approximated. What’s more, your solution looks more elegant.

  • @Eduardoalmeida actually in this example the switch is solving another problem, not the one presented here and it is questionable whether something would be cool to do in well modularized modern codes. The solution of the problem presented there is the same as here, but it was not the switch which made it possible. was the separation of what is a repetitive pattern from what varied.

  • But that’s the idea. I say what I want and the switch tells how LINQ has to do. The parameters are sent to the query only if they meet a condition set in switch. If I pass this to the controller there is no problem, after all, the controller defines the behavior of my system through decision structures and the switch That’s what I’m talking about.

  • Only have these fields in the table?

  • It’s just an illustrative example, it could have more fields. The purpose of the question is exactly to avoid code repetition problem if more fields need to be added. @GOKUSSJ4

  • @rubStackOverflow. See the example I answered.

Show 3 more comments

4 answers

4


I do not know if it fully meets what you need because the code presented is very lacking context, would have been easier if you had placed a MCVE. But I think this will do:

public static IEnumerable<Produto> Lista(IEnumerable<Produto> produtos) {
    return from p in produtos
        select new Produto {
            ProdutoId = p.ProdutoId,
            Descricao = p.Descricao,
            Preco = p.Preco,
            Estoque = p.Estoque
        };
}
public static IEnumerable<Produto> FiltreNome(IEnumerable<Produto> produtos, string descricao) {
    var query = from p in produtos
        where p.Descricao.StartsWith(descricao)
        select p;
    return Lista(query);
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

  • Understood, next time I’ll try to meet the standard MVCE.

0

Another way would be:

private static Produto CamposProduto(Produto p)
{
    return new Produto
    {
        ProdutoId = p.ProdutoId,
        Descricao = p.Descricao,
        Preco = p.Preco,
        Estoque = p.Estoque
    };
}

To take the fields would be:

var query = from p in Produtos
    select CamposProduto(p);
return query;

0

Place a DISCTINT() at the end of select

be more or less like this:

var query = from p in Produtos
    where p.Descricao.StartsWith(descricao)
    select new Produto
    {
        ProdutoId = p.ProdutoId,
        Descricao = p.Descricao,
        Preco = p.Preco,
        Estoque = p.Estoque
    }.DISCTINT();
return query;

I hope this helps

  • The repetition I refer to, is in the body of the question, is the query fields and not the result of it. @dacassussua

0

If your goal is to return only a few fields from your table you can use Extension methods, to work as if you were using any other Linq method, and you still have the facility to use as many filters as you need where you query and create typed list yet or leave Anonymous type

using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace stackoverflow
{
    public partial class BuscarProdutos : Page
    {
        protected void Load_Produtos()
        {
            using (var ctx = new stackoverflowEntities())
            {
                var query =  ctx.Produtos
                    .Where(p => p.Descricao.StartsWith("descricao")) // aqui você pode por quantos filtros forem necessarios.
                    .Vw_Produto(ctx); // aqui você chama seu Métodos de extensão. (Vw_Produto)

                // enquanto a query for um IQueryable você pode fazer filtro tipo
                bool campo1 = true, campo2 = true;
                if(campo1 == campo2)
                {
                    query = query.Where(p => p.ProdutoId == 1);
                }

                // para execulta sua query user o ToList(); ou em algum tipo de loop, isso lançara uma consulta 
                // no banco de dados
                var lista = query.ToList();
            }
        }
    }

    public class cvw_Produto
    {
        public string Descricao { get; internal set; }
        public int? Estoque { get; internal set; }
        public decimal? Preco { get; internal set; }
        public int ProdutoId { get; internal set; }
    }

    public static class ProdutoExt
    {
        public static IQueryable<cvw_Produto> Vw_Produto(
                this IQueryable<Produto> qrIn, stackoverflowEntities ctx)
        {
            return qrIn
                .Select(p => new cvw_Produto // Com tipo ou deixe só o new para ficar tipo anonimos.
                {
                    ProdutoId = p.ProdutoId,
                    Descricao = p.Descricao,
                    Preco = p.Preco,
                    Estoque = p.Estoque
                });
        }
    }
}

Browser other questions tagged

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