Como chamar um procedimento armazenado no EF Core 3.0 via FromSqlRaw

10

Migrei recentemente do EF Core 2.2 para o EF Core 3.0.

Infelizmente, não encontrei uma maneira de chamar um procedimento armazenado que retorna uma entidade.

No EF Core 2.0, era possível:

var spParams = new object[] { "bla", "xx" };
var createdPath = ModelContext.Paths.FromSql("AddNodeWithPathProc  @p0, @p1", spParams).Single();

No EF Core 3.0, o método FromSQLé substituído por FromSqlRaw. No entanto, não consegui chamar com êxito um procedimento armazenado e depois processar o valor. Isso é útil quando o procedimento armazenado insere dados no banco de dados.

Então, no EF Core 3.0, eu uso este código:

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc @p0, @p1", spParams).Single();

mas lançará uma exceção, porque o SQL gerado é inválido e se parece com isso:

exec sp_executesql N'SELECT TOP(2) [p].[PathId], [p].[Level], [p].[NodeId], [p].[NodePath], [p].[NodePathString]
FROM (
     @sql @p0, @p1
) AS [p]',N'@p0 nvarchar(4000),@p1 nvarchar(4000), @sql nvarchar(100)',@p0=N'1a',@p1=N'', @sql=N'AddNodeWithPathProc'

Eu tentei algumas variações, mas sem sucesso.

Estou começando a pensar que não é possível executar procedimentos armazenados com ModelContext.[IQueryable].FromSqlRaw. Na minha opinião, esse tipo derrota uma das principais razões FromSqlRawporque, para instruções de seleção normais, o LINQ é normalmente bom o suficiente.

Alguém sabe como usar procedimentos armazenados em combinação com FromSqlRaw EF Core 3.0? Qualquer ajuda é muito apreciada.

desde já, obrigado

PS: Eu sei que você pode executar um procedimento armazenado com this.Database.ExecuteSqlRaw(SQL, parameters). No entanto, dessa forma, não é possível recuperar nenhuma entidade consultada pelo procedimento armazenado.

Dan
fonte
2
Tente .ToList () em vez de .Single (). .Single () está gerando o wrapper "TOP (2)".
David Browne - Microsoft
minha solução temporária para o momento é a seguinte: this.ModelContext.ExecuteRawSql ("EXEC AddNodeWithPathProc @ p0, @ p1", spParams); var createdPath = ModelContext.Paths.FromSqlRaw ("SELECT TOP 1 * FROM dbo.Path ORDER BY PathID DESC"). Single (); No entanto, essa não é uma solução aceitável para produção.
Dan
sim .. ToList () funciona .. thanks a lot :-)
Dan

Respostas:

6

Solução (graças a David Browne, você deveria publicá-la como resposta):

Substituir Single por ToList funciona :-)

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc  {0}, {1}", nodeTitle, parentPathString).ToList();
Dan
fonte
1
var result=context.yourmodelclass.FromSqlInterpolated($"StoredProcedureName {param1},{param2}").tolist();

Você pode adicionar vários parâmetros, se necessário. Nota:

  • context => seu nome do banco de dados.
  • yourmodelclass => a classe na pasta de modelos criada para buscar o resultado da saída do resultado do procedimento armazenado.
Mohammad Irtaza
fonte
0

Não estou onde posso testar, mas acho que o seguinte funcionará:

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc {0}, {1}", parm1 parm2).Single();
Edney Holder
fonte
1
Não, isso não funciona. Apenas testei. O sql inválido :-(. Acredito que tenha algo a ver com o sql gerado. Se eu verificar o sql com o criador de perfil, ele sempre segue o esquema: sp_executesql 'SELECT * FROM {mySqlPassedInMethod}. saber como passar um procedimento armazenado neste código.Portanto, o método .net detecta que a string sql passada é para um procedimento armazenado e adapta o sql gerado de acordo ou existe uma maneira no T-SQL que eu não conheço (eu não sou um especialista)
Dan
0

tente separar SqlParameter:

SqlParameter param1 = new SqlParameter("@p0","value");
SqlParameter param2 = new SqlParameter("@p1","value");

var createdPath = ModelContext.Paths.FromSqlRaw("AddNodeWithPathProc @p0 @p1", param1, 
param2).Single();
ISTech
fonte
postou uma solução para sua postagem excluída abaixo.
jdweng
Apenas tentei e falhou :-(. O erro é: "System.InvalidCastException: 'O SqlParameterCollection aceita apenas objetos do tipo SqlParameter não nulos, não objetos SqlParameter.'". Não há sql enviado ao servidor sql (de acordo com sql profiler)
Dan
@jdweng Muito obrigado :) Esta solução que eu tenho ao fazer login no meu software e baixar o último arquivo XML atualizado com a última data, mas preciso de todos os dados histricamente das taxas sem perder. Portanto, tenho outra opção para definir datas e baixar o arquivo excel com as taxas, mas não sei como implementá-lo. executar um serviço no servidor? talvez os usuários não usem o software por uma semana, então eu perdi a semana inteira das taxas de câmbio.
ISTech
@ISTech: Veja a seguinte página: boi.org.il/en/Markets/Pages/explainxml.aspx que você pode adicionar ao URL de uma data. boi.org.il/currency.xml?rdate=20120101
jdweng
@ISTech: Atualizei o código abaixo para fazer um intervalo de datas.
Jdweng #
0

É extremamente estranho ... pouco antes de alguns dias atrás, tenho o mesmo problema e sigo este post. Eu recebi esta ligação:

 public IEnumerable<TableChange> GetTableLastChanges(string tableName, string keyColumn, out int synchronizationVersion)
    {
        var parameters = new[] {
            new SqlParameter("@table_name", SqlDbType.VarChar) { Direction = ParameterDirection.Input, Value = tableName },
            new SqlParameter("@key_column", SqlDbType.VarChar) { Direction = ParameterDirection.Input, Value = keyColumn },
            new SqlParameter("@synchronization_version", SqlDbType.BigInt) { Direction = ParameterDirection.InputOutput, Value = 0 }
        };

        var changes = this.TableChanges.FromSqlRaw("[dbo].[GetTableLastChanges] @table_name, @key_column, @synchronization_version OUTPUT", parameters).ToList();

        synchronizationVersion = Convert.ToInt32(parameters[2].Value);

        return changes;
    }

No momento, está tudo bem e esta chamada funciona como esperado. Portanto, devo admitir que não há problema com o retorno de conjuntos de dados e parâmetros para EF no Core 3.

juriko
fonte
0

Dê uma olhada aqui:

https://github.com/DarioN1/SPToCore

Este é um andaime para procedimento armazenado, ele pode ajudá-lo a trabalhar com sp.

Não é uma biblioteca de terceiros, ele gerou código c # puro para incluir no seu projeto que estende o dbContext atual para fornecer métodos de procedimentos armazenados, mapeamento de parâmetros e resultados classificados.

DarioN1
fonte