Entity Framework 7 con base de datos existente en .Net 5 MVC 6

asp.net-core-mvc c# entity-framework-core

Pregunta

Hola, estoy teniendo algunos problemas para extraer datos de una base de datos existente en Entity Framework 7 MVC 6. (He publicado el código del proyecto aquí ). He configurado appsettings.json con la cadena de conexión adecuada:

"Data": {
    "DefaultConnection": {
        "ConnectionString": "Data Source=localhost;Initial Catalog=Demo;Integrated Security=True"
}

Tengo mi contexto personalizado:

public class DatabaseContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Customer> Customers { get; set; }
}

Dos clases de poco:

[Table("Customers")]
public class Customer
{
    [Key]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string EmailAddress { get; set; }
    public DateTime Created { get; set; }
    public DateTime Updated { get; set; }
    public User User { get; set; }
    public bool Active { get; set; }
}

[Table("Users")]
public class User
{
    [Key]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string EmailAddress { get; set; }
    public DateTime Created { get; set; }
    public DateTime Updated { get; set; }
    public bool Active { get; set; }
}

Y estoy configurando el servicio en startup.cs

public Startup(IHostingEnvironment env)
    {
        // Set up configuration sources.

        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        if (env.IsDevelopment())
        {
            // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
            builder.AddUserSecrets();

            // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
            builder.AddApplicationInsightsSettings(developerMode: true);
        }

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; set; }

    // 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.AddApplicationInsightsTelemetry(Configuration);

        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<DatabaseContext>(options =>
                options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.AddMvc();

        // Add application services.

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        if (env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");

            // For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
            try
            {
                using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
                    .CreateScope())
                {
                    serviceScope.ServiceProvider.GetService<ApplicationDbContext>()
                         .Database.Migrate();
                }
            }
            catch { }
        }

        app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();

        app.UseIdentity();

        // To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

    // Entry point for the application.
    public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}

Mi controlador de usuarios:

[Route("[controller]")]
public class UsersController : Controller
{
    public DatabaseContext _context { get; set; }

    public UsersController(DatabaseContext context)
    {
        _context = context;
    }
    [Route("[action]")]
    public IActionResult Index()
    {
        using (_context)
        {
            List<User> users = _context.Users.ToList();
        }


        return View();
    }
}

Sigo recibiendo el siguiente error en la línea de lista cuando navego a la página de Usuarios / índice:

$ exception {"Referencia de objeto no establecida en una instancia de un objeto."} System.NullReferenceException

Por alguna razón, no está extrayendo la información de la base de datos. Lo creo en Microsoft SQLServer 2014. Y hay datos en la tabla de usuarios. ¿Me estoy perdiendo un paso o estoy tratando de acceder a los datos de manera incorrecta?

Respuesta aceptada

El problema principal se puede solucionar mediante el uso de

public UsersController([FromServices] DatabaseContext context)
{
    _context = context;
}

en lugar de

public UsersController(DatabaseContext context)
{
    _context = context;
}

Es posible usar

[FromServices]
public DatabaseContext _context { get; set; }

pero uno tiene que quitar el constructor public UsersController(DatabaseContext context) . No se recomienda la última forma, porque RC2 se cayó de la segunda. Ver el anuncio .

Los cambios anteriores corrigen el primer problema que tiene, pero la base de datos y los datos de prueba que utiliza producen un problema más, porque el campo Updated de sus tablas de Users y Customers contiene valores NULL . Así tienes que usar

public DateTime? Updated { get; set; }

en lugar de

public DateTime Updated { get; set; }

La forma en que lo recomendaría es el uso de la recomendación.

dnx ef dbcontext scaffold
    "Data Source=localhost;Initial Catalog=Demo;Integrated Security=True"
    EntityFramework.MicrosoftSqlServer --outputDir ..\Bestro\Model --verbose

que puede ejecutar en el mismo directorio donde está el proyecto principal.json (en src\JenSolo ). Envolví partes del comando en la nueva línea para una mejor lectura. Uno debe colocar todo en una línea de causa. El comando anterior creará clases de Users y Customers lugar de [Table("Users")]User y [Table("Customers")]Customer , pero puede usar el código como base y realizar todas las modificaciones necesarias de forma manual.

ACTUALIZADO: Me parece que el siguiente comando corresponde mejor a la generación de las clases de andamios:

dnx ef dbcontext scaffold
    "Data Source=localhost;Initial Catalog=Demo;Integrated Security=True"
    EntityFramework.MicrosoftSqlServer --outputDir ..\Bestro\Model --verbose
    --targetProject Bestro --dataAnnotations

Porque usas Class Library Bestro en el proyecto principal JenSolo. Debe ejecutar el comando anterior desde la línea de comandos con la carpeta ...\src\JenSolo como el directorio actual. Creará la carpeta Model en el proyecto de la Biblioteca de clases (Bestro). La carpeta Model contendrá muchos archivos *.cs : un archivo para cada tabla de base de datos y un archivo adicional DemoContext.cs , que contiene la clase DemoContext derivada de DbContext ( Demo es el nombre de la base de datos que usa). Debe eliminar la función OnConfiguring de DemoContext.cs para poder configurar la cadena de conexión a través de

services.AddEntityFramework()
   .AddSqlServer()
   .AddDbContext<DemoContext>(options =>
      options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

en ConfigureServices de Startup.cs del proyecto principal JenSolo .

ACTUALIZADO: A partir de .NET Core RC2, se debe usar el andamio dotnet ef dbcontext en lugar del dnx ef dbcontext scaffold .



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué