Funções de banco de dados
As funções de banco de dados são o equivalente de banco de dados dos métodos C#. Uma função de banco de dados pode ser invocada com zero ou mais parâmetros e calcula o resultado com base nos valores de parâmetro. A maioria dos bancos de dados, que usam SQL para consulta, tem suporte para funções de banco de dados. Portanto, o SQL gerado pela tradução de consulta do EF Core também permite invocar funções de banco de dados. Os métodos C# não precisam ser traduzidos estritamente para funções de banco de dados no EF Core.
- Um método C# pode não ter uma função de banco de dados equivalente.
- O método String.IsNullOrEmpty é traduzido para uma verificação nula e uma comparação com uma cadeia de caracteres vazia no banco de dados em vez de uma função.
- O método String.Equals(String, StringComparison) não tem o equivalente de banco de dados, pois a comparação de cadeia de caracteres não pode ser representada ou imitada facilmente em um banco de dados.
- Uma função de banco de dados pode não ter um método C# equivalente. O operador
??
em C#, que não tem nenhum método, é traduzido para a funçãoCOALESCE
no banco de dados.
Tipos de funções de banco de dados
A geração de SQL do EF Core dá suporte a um subconjunto de funções que podem ser usadas em bancos de dados. Essa limitação vem da capacidade de representar uma consulta no LINQ para a função de banco de dados fornecida. Além disso, cada banco de dados tem suporte variado de funções de banco de dados, portanto, o EF Core fornece um subconjunto comum. Um provedor de banco de dados é livre para estender a geração de SQL do EF Core para dar suporte a mais padrões. A seguir estão os tipos de funções de banco de dados aos quais o EF Core dá suporte e identifica exclusivamente. Esses termos também ajudam a entender quais traduções vêm integradas aos provedores do EF Core.
Funções internas versus funções definidas pelo usuário
As funções internas vêm com o banco de dados predefinido, mas as funções definidas pelo usuário são definidas explicitamente pelo usuário no banco de dados. Quando o EF Core traduz consultas para usar funções de banco de dados, ele usa funções internas para garantir que a função esteja sempre disponível no banco de dados. A distinção de funções internas é necessária em alguns bancos de dados para gerar o SQL corretamente. Por exemplo, o SqlServer requer que cada função definida pelo usuário seja invocada com um nome qualificado por esquema. Mas as funções internas no SqlServer não têm um esquema. O PostgreSQL define a função interna no esquema public
, mas ela pode ser invocada com nomes qualificados por esquema.
Funções de agregação versus funções escalares versus funções com valor de tabela
- Aa funções escalares usam valores escalares, como inteiros ou cadeias de caracteres, como parâmetros e retornam um valor escalar como resultado. As funções escalares podem ser usadas em qualquer lugar no SQL em que um valor escalar possa ser passado.
- As funções de agregação usam um fluxo de valores escalares como parâmetros e retornam um valor escalar como resultado. As funções de agregação são aplicadas em todo o conjunto de resultados da consulta ou em um grupo de valores gerados ao aplicar o operador
GROUP BY
. - As funções com valor de tabela usam valores escalares como parâmetros e retornam um fluxo de linhas como resultado. As funções com valor de tabela são usadas como uma fonte de tabela na cláusula
FROM
.
Funções niladic
As funções niladic são funções de banco de dados especiais que não têm parâmetros e devem ser invocadas sem parênteses. Elas são semelhantes ao acesso de propriedade/campo em uma instância em C#. As funções niladic diferem das funções sem parâmetro, pois estas exigem parênteses vazios. Não há nenhum nome especial para funções de banco de dados que exijam parênteses sempre. Outro subconjunto de funções de banco de dados com base na contagem de parâmetros são funções variádicas. As funções variádicas pode usar um número variado de parâmetros quando invocadas.
Mapeamentos de função de banco de dados no EF Core
O EF Core dá suporte a três maneiras diferentes de mapeamento entre funções C# e funções de banco de dados.
Mapeamento de função interna
Por padrão, os provedores do EF Core fornecem mapeamentos para várias funções internas no lugar de tipos primitivos. Por exemplo, String.ToLower() é traduzido para LOWER
no SqlServer. Essa funcionalidade permite que os usuários escrevam consultas no LINQ perfeitamente. Normalmente, fornecemos uma tradução no banco de dados que fornece o mesmo resultado que a função C# fornece no lado do cliente. Ás vezes, para fazer isso, a tradução real pode ser algo mais complicado do que uma função de banco de dados. Em alguns cenários, também fornecemos a tradução mais apropriada em vez de corresponder à semântica do C#. O mesmo recurso também é usado para fornecer traduções comuns para alguns dos acessos de membro do C#. Por exemplo, String.Length é traduzido para LEN
no SqlServer. Além dos provedores, os autores de plug-in também podem adicionar traduções adicionais. Essa extensibilidade é útil quando os plug-ins adicionam suporte para mais tipos, como tipos primitivos, e querem traduzir métodos no lugar deles.
Mapeamento de EF.Functions
Como nem todas as funções de banco de dados têm funções C# equivalentes, os provedores do EF Core têm métodos C# especiais para invocar determinadas funções de banco de dados. Esses métodos são definidos como métodos de extensão no lugar de EF.Functions
para serem usados em consultas LINQ. Esses métodos são específicos do provedor, pois estão intimamente vinculados a funções de banco de dados específicas. Portanto, um método que funciona para um provedor provavelmente não funcionará para nenhum outro provedor. Além disso, como a intenção desses métodos é invocar uma função de banco de dados na consulta traduzida, tentar avaliá-los no cliente resulta em uma exceção.
Mapeamento de função definido pelo usuário
Além dos mapeamentos fornecidos por provedores do EF Core, os usuários também podem definir o mapeamento personalizado. Um mapeamento definido pelo usuário estende a tradução de consulta de acordo com as necessidades do usuário. Essa funcionalidade é útil quando há funções definidas pelo usuário no banco de dados as quais o usuário deseja invocar a partir de sua consulta LINQ.