> ## Content Index
> Fetch the complete content index at: https://www.azurebrasil.cloud/llms.txt
> Use this file to discover other available public pages before exploring further.

# Adicionando o Entity Framework Core a uma Azure Function
- URL: https://www.azurebrasil.cloud/blog/adicionar-ef-a-uma-azure-function/
- Published: 2023-05-31T13:29:31.000Z
- Updated: 2023-05-31T13:29:31.000Z
- Author: Talles Valiatti

Esses dias me deparei com a tarefa de implementar o [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/?ref=azurebrasil.cloud) em uma [Azure Function](https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview?pivots=programming-language-csharp&ref=azurebrasil.cloud). Me deparei com uma situação na qual vale a pena ser compartilhada.

Sobre a *function* e o ambiente de desenvolvimento*,* temos a seguintes características:

- A *function* é do tipo [*isolated worker process*](https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?ref=azurebrasil.cloud#why-net-functions-isolated-worker-process)*;*
- Utilizei o [.NET 7](https://dotnet.microsoft.com/pt-br/download/dotnet/7.0?ref=azurebrasil.cloud);
- Utilizei o *[Visual Studio 2022 for Mac.](https://visualstudio.microsoft.com/pt-br/vs/mac/?ref=azurebrasil.cloud)*

Antes de seguir, caso seja a sua primeira vez lendo sobre Azure Functions, recomendo a leitura da [documentação oficial](https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview?pivots=programming-language-csharp&ref=azurebrasil.cloud). Além disso, eu já escrevi alguns posts sobre esse recurso de nuvem, você pode conferir [aqui](https://tallesvaliatti.com/enviando-mensagens-para-as-filas-do-storage-account-atrav%C3%A9s-das-azure-functions-de3a178b9aa9?source=collection%5Fhome---------3----------------------------) e [aqui](https://tallesvaliatti.com/avaliando-a-escalabilidade-das-azure-functions-1f5fec737167?ref=azurebrasil.cloud).

Inicialmente vamos criar o projeto de *functions* diretamente pela IDE*.*

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-24-at-10.55.13.png)

A *function* criada será do tipo [Timer trigger](https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?pivots=programming-language-csharp&tabs=python-v2%2Cin-process%2Cfunctionsv2&ref=azurebrasil.cloud).

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-24-at-10.56.17.png)

Para implementar o [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/?ref=azurebrasil.cloud), iremos adicionar os seguintes pacotes ao nosso projeto. Vale mencionar que estamos criando um banco de dados do zero (SQL Server), por isso utilizaremos a abordagem *[code-first](https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro?view=aspnetcore-7.0&ref=azurebrasil.cloud#initialize-db-with-test-data).*

```
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Design
```

No arquivo *local.settings.json*, vamos adicionar a *connectionString* do nosso banco de dados. Nesse caso, eu levantei um[SQL Servervia *docker*](https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-ver16&pivots=cs1-bash&ref=azurebrasil.cloud)no meu ambiente local*.*

```
{
    "IsEncrypted": false,
    "Values": {
      "AzureWebJobsStorage": "UseDevelopmentStorage=true",
      "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
      "ConnectionString": "YOUR-CONNECTION-STRING"
  }
}

```

É hora de criar um modelo simples de dados. Vamos declarar a classe *Book* com apenas duas propriedades.

```
using System;
namespace AzureFunctionEF.Models
{
	public class Book
	{
		public Guid Id { get; set; }

		public string Name { get; set; } = default!;
    }
}
```

Devemos também implementar a classe [*Context*](https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration/?ref=azurebrasil.cloud)*.* Observe que fizemos o[mapeamento](https://learn.microsoft.com/en-us/ef/core/modeling/?ref=azurebrasil.cloud) de como a classe *Book* será utilizada como base da tabela *Books* 

```
using System;
using AzureFunctionEF.Models;
using Microsoft.EntityFrameworkCore;

namespace AzureFunctionEF.Data
{
	public class Context : DbContext
	{
        public Context(DbContextOptions options) : base(options)
        {
        }

        public DbSet<Book> Books { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Book>()
                .ToTable("Books");
        }
    }
}
```

Com a classe *Context* implementada, já podemos fazer a configuração do *Entity Framework Core* na classe *Program.cs.* 

```
using AzureFunctionEF.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults();

builder.ConfigureServices((hostContext, services) =>
{
    string connectionString = hostContext.Configuration.GetSection("ConnectionString").Value!;

    services.AddDbContext<Context>(
        options => SqlServerDbContextOptionsExtensions.UseSqlServer(options, connectionString));
});

builder.Build().Run();
```

Para finalizar, basta fazermos a [injeção de dependência](https://learn.microsoft.com/pt-br/dotnet/core/extensions/dependency-injection?ref=azurebrasil.cloud) do *Context* na *function* criada por *default* no nosso projeto. Essa *function* irá basicamente criar um novo registro de *Book* a cada período determinado pelo[*trigger* da *function*](https://www.google.com/search?q=trigger+fuctions&oq=trigger+fuctions&aqs=chrome..69i57j0i433i512j0i512j0i433i512j0i131i433i512j0i67i650j0i512l4.2358j0j7&sourceid=chrome&ie=UTF-8&ref=azurebrasil.cloud)*.*

```
using System;
using AzureFunctionEF.Data;
using AzureFunctionEF.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace AzureFunctionEF
{
    public class DefaultFunction
    {
        private readonly ILogger _logger;
        private readonly Context _context;

        public DefaultFunction(ILoggerFactory loggerFactory, Context context)
        {
            _logger = loggerFactory.CreateLogger<DefaultFunction>();
            _context = context;
        }

        [Function("DefaultFunction")]
        public async Task RunAsync([TimerTrigger("0 */1 * * * *")] MyInfo myTimer)
        {
            _logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

            var id = Guid.NewGuid();

            await _context.Books.AddAsync(new Book
            {
                Id = id,    
                Name = $"Book_{id}"
            });

            await _context.SaveChangesAsync();

            _logger.LogInformation($"Next timer schedule at: {myTimer.ScheduleStatus.Next}");
        }
    }

    public class MyInfo
    {
        public MyScheduleStatus ScheduleStatus { get; set; }

        public bool IsPastDue { get; set; }
    }

    public class MyScheduleStatus
    {
        public DateTime Last { get; set; }

        public DateTime Next { get; set; }

        public DateTime LastUpdated { get; set; }
    }
}

```

Dito isso, já podemos gerar a primeira *[migration](https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli&ref=azurebrasil.cloud)* e fazer o [*update* do banco de dados](https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying?tabs=dotnet-core-cli&ref=azurebrasil.cloud#command-line-tools).

```
dotnet ef migrations add InitialMigration --verbose
```

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-24-at-11.15.19.png)

Observe que recebemos um erro, dizendo que a classe *Context* não pode ser criada.

```
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'Context'
```

Para resolver esse problema, devemos criar a classe *ContextFactory* que implementa *[IDesignTimeDbContextFactory](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.design.idesigntimedbcontextfactory-1?view=efcore-7.0&ref=azurebrasil.cloud).* Com isso podemos construir classes que herdam de [*DbContext*](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext?view=efcore-7.0&ref=azurebrasil.cloud) em *[design-time](https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli&ref=azurebrasil.cloud).* Recomendo a leitura deste conceito!

```
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

namespace AzureFunctionEF.Data
{
	public class ContextFactory : IDesignTimeDbContextFactory<Context>
    {
        public Context CreateDbContext(string[] args)
        {

            var index = Array.IndexOf(args, "--connection-string");

            if (index == -1)
                throw new Exception("Parameter --connection-string did not provide");

            string connectionString = args[index + 1];

            Console.WriteLine(connectionString);

            var optionsBuilder = new DbContextOptionsBuilder<Context>();
            optionsBuilder.UseSqlServer(connectionString);

            return new Context(optionsBuilder.Options);
        }
    }
}
```

Dessa forma, já podemos criar a *migration.* Precisaremos desta vez passar a *connection string* via parâmetro.

```
dotnet ef migrations add InitialMigration --verbose -- --connection-string '<YOUR-CONNECTION-STRING>'
```

É hora de [aplicarmos essa *migration* ao banco de dados](https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying?tabs=dotnet-core-cli&ref=azurebrasil.cloud).

```
dotnet ef database update --verbose -- --connection-string '<YOUR-CONNECTION-STRING>'
```

Podemos observar que tudo foi criado corretamente.

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-24-at-11.19.37.png)

Ao executarmos a *function,* depois de alguns ciclos*,* percebemos ela está salvando novos registros de forma correta*. O Entity Framework Core* foi implementado corretamente!

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-24-at-11.24.03.png)

Você já pode baixar o projeto por esse [](https://github.com/TallesValiatti/AzureCostManagementRestApi?ref=azurebrasil.cloud)[link](https://github.com/TallesValiatti/AzureFunctionEF?ref=azurebrasil.cloud), e não esquece de me seguir no [LinkedIn](https://www.linkedin.com/in/tallesvaliatti/?ref=azurebrasil.cloud)!

Até a próxima, abraços!