Então, aqui está o acordo - atualmente estou usando o EF Core 3.1 e digamos que tenho uma entidade:
public class Entity
{
public int Id { get; set; }
public int AnotherEntityId { get; set; }
public virtual AnotherEntity AnotherEntity { get; set; }
}
Quando acesso a DbSet<Entity> Entities
maneira normal, incluo AnotherEntity como:
_context.Entities.Include(e => e.AnotherEntity)
e isso funciona. Por que não, certo? Então eu vou com:
_context.Entities.FromSqlRaw("SELECT * FROM Entities").Include(e => e.AnotherEntity)
e isso também funciona. Ambos me devolvem a mesma coleção de objetos unidos ao AnotherEntity. Então eu uso um procedimento armazenado que consiste na mesma consulta SELECT * FROM Entities
denominada spGetEntities:
_context.Entities.FromSqlRaw("spGetEntities")
adivinha? Isso também funciona. Dá-me a mesma saída, mas sem entrar no AnotherEntity, obviamente. No entanto, se eu tentar adicionar o Incluir assim:
_context.Entities.FromSqlRaw("spGetEntities").Include(e => e.AnotherEntity)
Estou obtendo:
FromSqlRaw ou FromSqlInterpolated foi chamado com SQL não-composable e com uma consulta compondo sobre ele. Considere chamar
AsEnumerable
após o método FromSqlRaw ou FromSqlInterpolated para executar a composição no lado do cliente.
Mesmo que a saída de _context.Entities.FromSqlRaw("SELECT * FROM Entities")
e _context.Entities.FromSqlRaw("spGetEntities")
seja idêntica.
Não consegui encontrar uma prova de que posso ou não posso fazer isso com o EF Core 3.1, mas se alguém pudesse me dar alguma sugestão de possibilidade dessa abordagem, seria bom.
Além disso, se houver outra maneira de associar entidades usando o procedimento armazenado, provavelmente o aceitaria como a solução do meu problema.
Respostas:
Em breve, você não pode fazer isso (pelo menos para SqlServer). A explicação está contida na documentação do EF Core - Consultas SQL não processadas - Compondo com LINQ :
Além disso, uma vez que
Include
/ThenInclude
requer o EF CoreIQueryable<>
,AsEnumerable
/AsAsyncEnumerable
etc. não é uma opção. Você realmente precisa de SQL composível, portanto os procedimentos armazenados não são uma opção.Porém, em vez de procedimentos armazenados, você pode usar TVF (Table-Valued Functions) ou exibições de banco de dados porque elas são composíveis (
select * from TVF(params)
ouselect * from db_view
).fonte
No meu caso, eu estava convertendo EF de trabalho
FromSql()
com um código de procedimento armazenado 2.1 para 3.1. Igual a:Onde
AccountSums
é um SP.A única coisa que eu precisava fazer era usar
FromSqlRaw()
e adicionarIgnoreQueryFilters()
para que funcionasse novamente. Igual a:Isso é mencionado nos comentários, mas eu perdi isso a princípio, incluindo isso aqui.
fonte