EF 1.1 Database First .NET Core Visual Studio 2017

En artículos previos, hemos visto el acercamiento Code First con Entity Framework para el desarrollo de aplicaciones conectadas contra base de datos. En esta oportunidad veremos otro método para realizar este tipo de aplicación, utilizaremos Database First, pero ¿Qué es Database First?

Database First

A diferencia de Code First, donde podemos comenzar escribiendo nuestra clases, restricciones y luego aplicarlas mediante Migrations hacia la base de datos para mantenerla actualizada, Database First es un acercamiento donde lo primero que tenemos son las entidades de base de datos y debemos traer dicho modelo a nuestra aplicación.

Entity Framework, nos provee los mecanismos necesarios para en forma automática traer nuestro modelo entidad relación de base de datos, al modelo necesario de nuestro dominio de aplicación.

How to:

Llegó el momento, veremos la capacidad de Entity Framework Core en este pequeño tutorial.

Prerrequisitos

  • Visual Studio 2017 (Community Edition en mi caso)

Primero generamos un proyecto de .NET Core, en este caso un proyecto web:

2

Para contar con soporte para Entity Framework Core, debemos agregar el paquete NuGet, para ello lo haremos ejecutando la siguiente línea en la consola de administración de paquetes NuGet:

Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.Tools
Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design

Base de datos

Nuestra base de datos contiene las siguientes entidades:

Books

  • Id (PK)
  • Name
  • AuthorId (FK)

Authors

  • Id (PK)
  • Name
  • Surname

El desafío es generar nuestro modelo basado en estas entidades de base de datos, mediante las herramientas ofrecidas por Entity Framework.

Generando nuestro modelo de base de datos

Lo primero que haremos es generar la base de datos en este caso en LocalDb, pero también podemos utilizar SQL Server. Para ello ejecutamos el siguiente script en el SQL Management Studio o en SQL Server Object Explorer

USE [master]
GO

CREATE DATABASE [DatabaseFirst]

GO

USE [DatabaseFirst]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Authors](
	[Id] [int] NOT NULL,
	[Name] [varchar](30) NOT NULL,
	[Surname] [varchar](30) NOT NULL,
 CONSTRAINT [PK_Authors] PRIMARY KEY CLUSTERED
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Books](
	[Id] [int] NOT NULL,
	[Name] [varchar](40) NOT NULL,
	[AuthorId] [int] NOT NULL,
 CONSTRAINT [PK_Books] PRIMARY KEY CLUSTERED
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[Books]  WITH CHECK ADD  CONSTRAINT [FK_Books_Authors] FOREIGN KEY([AuthorId])
REFERENCES [dbo].[Authors] ([Id])
GO
ALTER TABLE [dbo].[Books] CHECK CONSTRAINT [FK_Books_Authors]
GO
USE [master]
GO
ALTER DATABASE [DatabaseFirst] SET  READ_WRITE
GO

Generando nuestro modelo a partir de la base de datos

Es momento de generar nuestras entidades de software, utilizando las entidades de base de datos. Para ello utilizamos la consola de NuGet. (Tools –> NuGet Package Manager –> Package Manager Console).

Generamos una carpeta llamada Models, en el proyecto y luego ejecutamos el siguiente comando:

Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=DatabaseFirst;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models

Como pueden observar si utilizan SQL Server, deben cambiar la cadena de conexión en el parámetro Server.

Si todo sale bien, veremos que tenemos generadas en forma automática las clases Authors, Books y el DBContext

using System;
using System.Collections.Generic;

namespace DatabaseFirst.EF.Demo.Models
{
    public partial class Authors
    {
        public Authors()
        {
            Books = new HashSet<Books>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }

        public virtual ICollection<Books> Books { get; set; }
    }
}
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace DatabaseFirst.EF.Demo.Models
{
    public partial class DatabaseFirstContext : DbContext
    {
        public virtual DbSet<Authors> Authors { get; set; }
        public virtual DbSet<Books> Books { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            #warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=DatabaseFirst;Trusted_Connection=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Authors>(entity =>
            {
                entity.Property(e => e.Id).ValueGeneratedNever();

                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasColumnType("varchar(30)");

                entity.Property(e => e.Surname)
                    .IsRequired()
                    .HasColumnType("varchar(30)");
            });

            modelBuilder.Entity<Books>(entity =>
            {
                entity.Property(e => e.Id).ValueGeneratedNever();

                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasColumnType("varchar(40)");

                entity.HasOne(d => d.Author)
                    .WithMany(p => p.Books)
                    .HasForeignKey(d => d.AuthorId)
                    .OnDelete(DeleteBehavior.Restrict)
                    .HasConstraintName("FK_Books_Authors");
            });
        }
    }
}

Si lo desean, pueden renombrar a singular las clases generadas automáticamente.

Inyección de dependencias

Como concepto fundamental de ASP.NET Core, los servicios son registrados como inyección de dependencias durante el inicio de la aplicación, por lo que debemos registrar nuestro servicio DatabaseFirstContext.

Para ello removeremos la configuración del contexto de base de datos que se encuentra especificada en el archivo DatabaseFirstContext.cs.


protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    #warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
    optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;");
}

Agregamos el siguiente constructor que permite pasar la configuración mediante inyección de dependencias:

        public DatabaseFirstContext(DbContextOptions<DatabaseFirstContext> options)
            : base(options)
         { }

Registrar y configurar nuestro contexto en el Startup.cs

Importamos los siguientes espacios de nombres utilizando Using:

using DatabaseFirst.EF.Demo.Models;
using Microsoft.EntityFrameworkCore;

Luego en el metodo ConfigureServices, agregamos el siguiente código:

public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();

            var connection = @"Server=(localdb)\mssqllocaldb;Database=DatabaseFirst;Trusted_Connection=True;";
            services.AddDbContext<DatabaseFirstContext>(options => options.UseSqlServer(connection));
        }

De esta forma estamos registrando nuestro contexto como servicio, dejándolo disponible para el uso de cualquier controller.

Por simplicidad dejamos el string de conexión dentro del método, pero una aplicación productiva real, debería estar en un archivo de configuración como puede ser appsettings.json en .NET Core.

En el caso que lo deseen pueden configurarlo de la siguiente forma:

        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();

            //var connection = @"Server=(localdb)\mssqllocaldb;Database=DatabaseFirst;Trusted_Connection=True;";
            //services.AddDbContext<DatabaseFirstContext>(options => options.UseSqlServer(connection));

            services.AddDbContext<DatabaseFirstContext>(options => options.UseSqlServer(
               Configuration.GetConnectionString("DefaultConnection"))
           );

En el archivo appsettings.json debemos configurar el ConnectionString de la siguiente forma:

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },

  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=DatabaseFirst;Trusted_Connection=True;"
  }
}

Conclusión

Como podemos observar, utilizando el modelo DatabaseFirst con Entity Framework podemos generar en forma automática las entidades a partir de una base de datos existente. Este enfoque es el más utilizado para proyectos grandes o productivos ya que muchas veces los desarrolladores “heredan” una base de datos generada por los DBA o en otros casos se comienza haciendo el diseño relacional de problema que debemos solucionar.

En este artículo, hemos cubierto lo básico como para poder iniciarnos en el desarrollo con el acercamiento Database First.

Pueden descargar o actualizar el código desde GitHub

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: