c# - with - vs code add new controller




Como posso chamar um procedimento armazenado do SQL usando o EntityFramework 7 e o Asp.Net 5 (4)

Nos últimos dias, estou procurando alguns tutoriais sobre como chamar um Stored Procedure de dentro de um método de controlador de Web API usando o EntityFramework 7 .

Todos os tutoriais que eu vim estão mostrando o contrário, ou seja, a abordagem Code First . Mas eu já tenho um banco de dados e preciso usá-lo para criar uma Web API . Várias lógicas de negócios já estão escritas como Procedimentos armazenados e exibições, e eu tenho que consumir as da minha API da Web.

Pergunta 1: É possível continuar com a abordagem do Database First com o EF7 e consumir objetos de banco de dados como acima?

Instalei o EntityFramework 6.1.3 no meu pacote pelo seguinte comando do NuGet :

install-package EntityFramework que adiciona a versão 6.1.3 ao meu projeto, mas começa imediatamente a me mostrar a mensagem de erro (veja a captura de tela abaixo). Não tenho idéia de como resolver isso.

Eu tenho outro projeto de teste em project.json , posso ver duas entradas, como a seguir:

"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final", "EntityFramework.MicrosoftSqlServer.Design": "7.0.0-rc1-final",

No entanto, quando estou pesquisando no gerenciador de pacotes Nu-Get , não vejo esta versão! Apenas 6.1.3 está chegando.

Meu principal objetivo é consumir procedimentos e exibições armazenados já escritos de um banco de dados existente.

1) Não quero usar o ADO.Net , mas gostaria de usar o ORM usando o EntityFramework

2) Se o EntityFramework 6.1.3 chamar Stored Procs e Views Stored Procs de um banco de dados já existente, como posso resolver o erro (captura de tela)?

Qual é a melhor prática para conseguir isso?


Assim como a resposta acima, você pode simplesmente usar o FromSQL () em vez de SqlQuery <> ().

context.Set().FromSql("[dbo].[GetFoo] @Bar = {0}", 45);

Espero entender corretamente seu problema. Você possui o STORED PROCEDURE, por exemplo, dbo.spGetSomeData , no banco de dados, que retorna a lista de alguns itens com alguns campos e precisa fornecer os dados do método da API da Web.

A implementação pode ser sobre o seguinte. Você pode definir um DbContext vazio como:

public class MyDbContext : DbContext
{
}

e para definir appsettings.json com a cadeia de conexão com o banco de dados

{
  "Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=MyDb;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  }
}

Você deve usar Microsoft.Extensions.DependencyInjection para adicionar MyDbContext ao

public class Startup
{
    // property for holding configuration
    public IConfigurationRoot Configuration { get; set; }

    public Startup(IHostingEnvironment env)
    {
        // Set up configuration sources.
        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
            .AddEnvironmentVariables();
        // save the configuration in Configuration property
        Configuration = builder.Build();
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc()
            .AddJsonOptions(options => {
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<MyDbContext>(options => {
                options.UseSqlServer(Configuration["ConnectionString"]);
            });
    }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ...
    }
}

Agora você pode implementar sua ação WebApi da seguinte maneira:

[Route("api/[controller]")]
public class MyController : Controller
{
    public MyDbContext _context { get; set; }

    public MyController([FromServices] MyDbContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async IEnumerable<object> Get()
    {
        var returnObject = new List<dynamic>();

        using (var cmd = _context.Database.GetDbConnection().CreateCommand()) {
            cmd.CommandText = "exec dbo.spGetSomeData";
            cmd.CommandType = CommandType.StoredProcedure;
            // set some parameters of the stored procedure
            cmd.Parameters.Add(new SqlParameter("@someParam",
                SqlDbType.TinyInt) { Value = 1 });

            if (cmd.Connection.State != ConnectionState.Open)
                cmd.Connection.Open();

            var retObject = new List<dynamic>();
            using (var dataReader = await cmd.ExecuteReaderAsync())
            {
                while (await dataReader.ReadAsync())
                {
                    var dataRow = new ExpandoObject() as IDictionary<string, object>;
                    for (var iFiled = 0; iFiled < dataReader.FieldCount; iFiled++) {
                        // one can modify the next line to
                        //   if (dataReader.IsDBNull(iFiled))
                        //       dataRow.Add(dataReader.GetName(iFiled), dataReader[iFiled]);
                        // if one want don't fill the property for NULL
                        // returned from the database
                        dataRow.Add(
                            dataReader.GetName(iFiled),
                            dataReader.IsDBNull(iFiled) ? null : dataReader[iFiled] // use null instead of {}
                        );
                    }

                    retObject.Add((ExpandoObject)dataRow);
                }
            }
            return retObject;
        }
    }
}

O código acima é executado apenas usando exec dbo.spGetSomeData e use dataRader para ler todos os resultados e salvá-los no objeto dynamic . Se você fizer uma $.ajax de api/My , obterá os dados retornados de dbo.spGetSomeData , que você pode usar diretamente no código JavaScript. O código acima é muito transparente. Os nomes dos campos do conjunto de dados retornados por dbo.spGetSomeData serão os nomes das propriedades no código JavaScript. Você não precisa gerenciar nenhuma classe de entidade no seu código C # de forma alguma. Seu código C # não possui nomes de campos retornados do procedimento armazenado. Portanto, se você estender / alterar o código de dbo.spGetSomeData (renomeie alguns campos, adicione novos campos), será necessário ajustar apenas seu código JavaScript, mas nenhum código C #.


Usando o conector MySQL e o Entity Framework core 2.0

Meu problema foi que eu estava recebendo uma exceção como fx. Ex.Message = "A coluna requerida 'body' não estava presente nos resultados de uma operação 'FromSql'.". Portanto, para buscar linhas por meio de um procedimento armazenado dessa maneira, você deve retornar todas as colunas para o tipo de entidade ao qual o DBSet está associado, mesmo que você não precise de todos os dados para esta chamada específica.

var result = _context.DBSetName.FromSql($"call storedProcedureName()").ToList(); 

OU com parâmetros

var result = _context.DBSetName.FromSql($"call storedProcedureName({optionalParam1})").ToList(); 

DbContext possui uma propriedade Database , que mantém uma conexão com o banco de dados com a qual você pode fazer o que quiser:

context.Database.SqlQuery<Foo>("exec [dbo].[GetFoo] @Bar = {0}", bar);

No entanto, em vez de fazer isso em suas ações de API da Web, sugiro adicionar um método ao seu contexto ou a qualquer serviço / repositório que interaja com o seu contexto. Em seguida, basta chamar esse método em sua ação. Idealmente, você deseja manter todo o seu material SQL em um só lugar.





ef-database-first