Estou trabalhando com C # e .NET Framework 4.5.1 recuperando dados de um banco de dados SQL Server com Entity Framework 6.1.3.
Eu tenho isto:
codes = codesRepo.SearchFor(predicate)
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();
E quando eu o executo, recebo esta mensagem:
Apenas construtores e inicializadores sem parâmetros têm suporte no LINQ to Entities.
Não sei como devo criar a Tupla, porque todos os exemplos que encontrei são em sua maioria como este.
Eu tentei isso:
codes = codesRepo.SearchFor(predicate)
.Select(c => Tuple.Create(c.Id, c.Flag))
.ToList();
E obter este erro:
LINQ to Entities não reconhece o método 'System.Tuple`2 [System.String, System.Byte] Create [String, Byte] (System.String, Byte)' e este método não pode ser convertido em uma expressão de armazenamento.
Onde está o problema?
c#
entity-framework
linq
tuples
VansFannel
fonte
fonte
Respostas:
Embora a resposta por octavioccl funcione, é melhor primeiro projetar o resultado da consulta no tipo anônimo e, em seguida, mudar para enumerável e convertê-lo em tupla. Desta forma, a sua consulta recuperará da base de dados apenas os campos necessários.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Nota: A regra acima se aplica ao EF6. EF Core naturalmente suporta tuplas (em projeção ou como chaves de junção / grupo) via construtor de tupla, por exemplo, a consulta original simplesmente funciona
codes = codesRepo.SearchFor(predicate) .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
mas não o
Tuple.Create
método (EF Core 2.x).fonte
.Select(c => new { c.Id, c.Flag, c.Foo?.Code })
não funciona.?.
não é compatível com árvores de expressão. Mas além disso, você pode estender o tipo anônimo com quantos valores quiser - apenas não se esqueça de nomeá-los quando necessário :) por exemploc => new { c.Id, c.Flag, Code = (int?)c.Foo.Code }
Apenas uma resposta atualizada para C # 7, agora você pode usar uma sintaxe mais simples para criar ValueTuples.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => (c.Id, c.Flag)) .ToList();
Você pode até nomear as propriedades da tupla agora:
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) // anonymous type .AsEnumerable() .Select(c => (Id: c.Id, Flag: c.Flag)) // ValueTuple .ToList();
Portanto, em vez de usá-lo como Item1 ou Item2, você pode acessá-lo como Id ou Flag.
Mais documentos sobre como escolher entre anônimo e tupla
fonte
Experimente isto:
Foi informado que isso não está aceitando no LINQ para entidades.
Outra opção seria puxar o resultado para a memória antes de selecionar. Se você vai fazer isso, eu recomendaria fazer toda a filtragem antes de .AsEnumerable (), pois isso significa que você está apenas obtendo os resultados desejados, em vez de retirar toda a tabela e, em seguida, filtrar.
também Tuple.Create (c.Id, c.Flag) pode ser alterado para novo Tuple (c.Id, c.Flag) se você quiser tornar o código um pouco mais explícito nos tipos de tuplas
fonte
Nas entidades linq to, você pode projetar em um tipo anônimo ou DTO. Para evitar esse problema, você pode usar o
AsEnumerable
método de extensão:codes = codesRepo.SearchFor(predicate).AsEnumerable(). .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Este método permite trabalhar com Linq to Object ao invés de Linq to Entities , então após chamá-lo, você pode projetar o resultado de sua consulta no que você precisar. A vantagem de usar em
AsEnumerable
vez dissoToList
é queAsEnumerable
não executa a consulta, preserva a execução adiada. É uma boa ideia sempre filtrar seus dados antes de chamar um desses métodos.fonte
Eu encontrei a resposta:
fonte
Use este método para fazer isso e use o assíncrono.
var codes = await codesRepo.SearchFor(predicate) .Select(s => new { Id = s.Id, Flag = s.Flag }).FirstOrDefaultAsync(); var return_Value = new Tuple<string, byte>(codes.Id, codes.Flag);
fonte
Apenas meus dois centavos: isso me surpreendeu algumas vezes com os nomes dos tipos:
Alguns exemplos complicados:
private Tuple<string, byte> v1() { return new Tuple<string, byte>("", 1); } private (string, int) v2() { return ("", 1); } private (string Id, byte Flag) v3() { return ("", 1); }
Saudações.
fonte
public (string Id, byte Flag) SearchFor(Expression predicate)
, mas isso não vem ao caso. Dois centavos não devem ser uma resposta, mas um comentário.