none
Resgatar mais de um id na condição "where" RRS feed

  • Pergunta

  • Então o que estou tentando fazer no Linq é uma consulta como essa abaixo,

    select * from tbl_livros where id in (1, 2, 3)

    os valores 1, 2 e 3 eu to passsando pro meu metodo de consulta mas nao estou sabendo como escrever o LinQ apropriado pra realizar uma consulta dessa acima. Alguem ja fez isso? Alguem pode me ajudar?

    Att, 

    Fábio Muniz.

    segunda-feira, 19 de dezembro de 2011 11:21

Respostas

  • A questão ai é a seguinte, você está aplicando um NEW após o seu select sem informar a qual classe deverá ser instânciada, com isso você está criando um tipo anônimo em tempo de execução. por isso você não está conseguido fazer este retorno. 

    o correto seria você fazer algo assim:

                var consulta = (from c in myCodeFirst.Vendas
                                join d in myCodeFirst.Usuarios on c.Cliente.Id equals d.Id
                                select new ClienteVendasTO()
                                {
                                    Cliente = d.Nome,
                                    Produto = c.Produto
                                }).ToList();
    

    claro que implementando para seu caso


    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 16:53
    Moderador
  • o código ficou meio complexo mesmo

    para você utilizar seria algo assim:

    List<int> Ids = new List<int>() { 1, 3 };
    
     var query = DataContext.tbl_solicitacoes.Where((BuildContainsExpression<tbl_solicitacoes, int>(tbl=> tbl.id, Ids)));
    

    trata-se de uma chamada passando passando valores por generics


    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 19:05
    Moderador
  • Amigo, bom dia

    para você utilizar o IN em uma consulta no LINQ, você precisa montar uma lista com os valores previamente e então procurar se o valor desejado está dentro dessa lista, por exemplo:

    List<int> Ids = new List<int>() { 1, 3 };
    
                var query = (from c in myCodeFirst.Vendas
                             where Ids.Contains(c.id)
                             select c).ToList();
    



    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 11:29
    Moderador
  • Olá Fabinhu,

    O segredo é criar um array, um list ou um IEnumerable com os valores que funcionaram como filtro.

    E sua query deve ficar assim:

    int[] values = new int[] { 1, 2, 3, 4, 5 };
    
    var query = Collection.Where(t => values.Contains(t.Id));
    

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    segunda-feira, 19 de dezembro de 2011 11:29
    Moderador
  • Se você tiver usando EF anterior ao 4 e o contains não funciona

    eu encontrei na internet, uma solução alternativa (workaround) bastante interessante e reutilizavel

    consite em você publicar este método:

            static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
            {
                if (null == valueSelector) { throw new
                    ArgumentNullException("valueSelector"); }
                if (null == values) { throw new ArgumentNullException("values"); }
                ParameterExpression p = valueSelector.Parameters.Single();
                if (!values.Any())
                {
                    return e => false;
                }
                var equals = values.Select(value =>
                    (Expression)Expression.Equal(valueSelector.Body, 
                    Expression.Constant(value,
                    typeof(TValue))));
                var body = equals.Aggregate<Expression>((accumulate, equal) =>
                    Expression.Or(accumulate, equal));
                return Expression.Lambda<Func<TElement, bool>>(body, p);
            }
    

    ele utiliza as classes do namespace System.Linq.Expressions;

    minha consulta ficaria assim utilizando essa solução:

                List<int> Ids = new List<int>() { 1, 3 };
    
                var query = myCodeFirst.Vendas.Where((BuildContainsExpression<Venda, int>(venda => venda.id, Ids)));
    
                var resultado = query.ToList();
    



    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 16:43
    Moderador

Todas as Respostas

  • Amigo, bom dia

    para você utilizar o IN em uma consulta no LINQ, você precisa montar uma lista com os valores previamente e então procurar se o valor desejado está dentro dessa lista, por exemplo:

    List<int> Ids = new List<int>() { 1, 3 };
    
                var query = (from c in myCodeFirst.Vendas
                             where Ids.Contains(c.id)
                             select c).ToList();
    



    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 11:29
    Moderador
  • Olá Fabinhu,

    O segredo é criar um array, um list ou um IEnumerable com os valores que funcionaram como filtro.

    E sua query deve ficar assim:

    int[] values = new int[] { 1, 2, 3, 4, 5 };
    
    var query = Collection.Where(t => values.Contains(t.Id));
    

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    segunda-feira, 19 de dezembro de 2011 11:29
    Moderador
  • Oi  Olavo, 

    Valeu por ter respondido. Eu tentei esse codigo q vc me passou mas ainda nao deu certo eu queria mesmo q o resultado dessa pesquisa fossem os registros da tabela. pra facilitar vou postar meu metodo aki pra vc ter uma ideia do q eu to tentando fazer:

     

    public IList<tbl_solicitacoes> mGetSolicitacoesByIds(string[] idSolicitacao)

            {

                List<int> Ids = new List<int>();

     

                foreach (string item in idSolicitacao)

                {

                    Ids.Add(int.Parse(item));

                }

     

                return (from f in this.DataContext.tbl_solicitacoes

                        where Ids.Contains(f.id)

                        select f).ToList();

     

            }

    quando eu rodo esse metodo ele me retorna o seguinte erro:

    LINQ to Entities não reconhece o método 'Boolean Contains(Int32)', que não pode ser convertido em uma expressão de armazenamento.

    Eu queria mesmo os registro da tabela no caso seriam esses registros aki dentro da minha IList<tbl_solicitacoes>:

    id tipo data

    1 Ferias 12/12/2011

    2 Admissao 13/12/2011

    no caso essa pesquisa ai acima no banco sairia assim:

    select * from tbl_solicitacoes where id in (1,2);

    segunda-feira, 19 de dezembro de 2011 15:59
  • Então Olavo, 

     

    Consegui de outra forma mas nao sei se essa é a melhor forma:

    public IList<tbl_solicitacoes> mGetSolicitacoesByIds(string[] idSolicitacao)

            {

                IList<tbl_solicitacoes> aListSolicitacoes = new List<tbl_solicitacoes>();

     

                foreach (string item in idSolicitacao)

                {

                    var query = (from f in this.DataContext.tbl_solicitacoes

                        where f.id.Equals(int.Parse(item.ToString()))

                        select f).FirstOrDefault();

     

                    aListSolicitacoes.Add(query);

                }

     

                return aListSolicitacoes;

     

            }

     

    Se tiver um jeito melhor de fazer isso q eu to querendo vc pode me dar uma dica?

    segunda-feira, 19 de dezembro de 2011 16:23
  • qual a versão do EF que você está usando ? 
    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 16:25
    Moderador
  • To usando MVC2, framework 3.5 
    segunda-feira, 19 de dezembro de 2011 16:39
  • cara posso aproveitar esse topico pra fazer uma outra pergumta... eh sobre LinQ tbm mas envolve duas tabelas.

    Eu acabei criando um tipo diferente pro metodo me retornar algumas colunas especificas mas nao to conseguindo fazer nao ele alega que falta fazer um cast se vc puder me ajudar com isso esse eh o metodo q eu to tentando rodar nao sei se escrevi certo.

     

    public IList<_RhFunFeriasTO> mGetSolicitacaoFeriasById()

            {

                return (from f in this.DataContext.tbl_ferias

                        join s in this.DataContext.tbl_solicitacoes on f.id equals s.id_tp_solicitacao

                        join u in this.DataContext.tbl_usuario on s.tbl_usuario.id equals u.id

                        where s.tipo == "Férias"

                        select new

                        {

                            f.id,

                            f.dt_ini_pa,

                            f.dt_fim_pa,

                            f.dias_gozados,

                            f.dias_ferias_restantes,

                            f.qtd_faltas,

                            f.qtd_dias_direito_ferias,

                            f.qtd_dias_ferias,

                            f.dt_ini_ferias,

                            f.abono_pecuniario,

                            f.adiantamento,

                            f.emprestimo,

                            f.dt_ini_abono,

                            u.cpf,

                            u.filial

                        }).ToList();

     

            }

     

    Obs: _RhFunFerias é uma classe q eu criei pra poder me retornar nesse tipo do select das colunas.
    • Editado fabinhuuudf10 segunda-feira, 19 de dezembro de 2011 16:43
    segunda-feira, 19 de dezembro de 2011 16:42
  • Se você tiver usando EF anterior ao 4 e o contains não funciona

    eu encontrei na internet, uma solução alternativa (workaround) bastante interessante e reutilizavel

    consite em você publicar este método:

            static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
            {
                if (null == valueSelector) { throw new
                    ArgumentNullException("valueSelector"); }
                if (null == values) { throw new ArgumentNullException("values"); }
                ParameterExpression p = valueSelector.Parameters.Single();
                if (!values.Any())
                {
                    return e => false;
                }
                var equals = values.Select(value =>
                    (Expression)Expression.Equal(valueSelector.Body, 
                    Expression.Constant(value,
                    typeof(TValue))));
                var body = equals.Aggregate<Expression>((accumulate, equal) =>
                    Expression.Or(accumulate, equal));
                return Expression.Lambda<Func<TElement, bool>>(body, p);
            }
    

    ele utiliza as classes do namespace System.Linq.Expressions;

    minha consulta ficaria assim utilizando essa solução:

                List<int> Ids = new List<int>() { 1, 3 };
    
                var query = myCodeFirst.Vendas.Where((BuildContainsExpression<Venda, int>(venda => venda.id, Ids)));
    
                var resultado = query.ToList();
    



    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 16:43
    Moderador
  • A questão ai é a seguinte, você está aplicando um NEW após o seu select sem informar a qual classe deverá ser instânciada, com isso você está criando um tipo anônimo em tempo de execução. por isso você não está conseguido fazer este retorno. 

    o correto seria você fazer algo assim:

                var consulta = (from c in myCodeFirst.Vendas
                                join d in myCodeFirst.Usuarios on c.Cliente.Id equals d.Id
                                select new ClienteVendasTO()
                                {
                                    Cliente = d.Nome,
                                    Produto = c.Produto
                                }).ToList();
    

    claro que implementando para seu caso


    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 16:53
    Moderador
  • Oi Olavo, 

    Era exatamente isso que eu estava tentando fazer mt obrigado mesmo.

    Mas quanto a esse metodo q vc me mandou eu tentei usa-la mas na chamada:

     myCodeFirst.Vendas.Where((BuildContainsExpression<Venda, int>(venda => venda.id, Ids)));

    
    
    BuildContainsExpression essa chamada aki nao é realizada nao, nao consegui entender direito o codigo.

    mas enfim vou tentar usa-lo mais a frente mto obrigado mesmo pela ajuda cara!

    segunda-feira, 19 de dezembro de 2011 18:46
  • o código ficou meio complexo mesmo

    para você utilizar seria algo assim:

    List<int> Ids = new List<int>() { 1, 3 };
    
     var query = DataContext.tbl_solicitacoes.Where((BuildContainsExpression<tbl_solicitacoes, int>(tbl=> tbl.id, Ids)));
    

    trata-se de uma chamada passando passando valores por generics


    Olavo Oliveira Neto
    http://olavooneto.wordpress.com
    Twitter @Olavooneto
    Se for útil marque como resposta e faça um Developer feliz :)
    segunda-feira, 19 de dezembro de 2011 19:05
    Moderador