【问题标题】:Entity Framework 7 With Existing Database in .Net 5 MVC 6.Net 5 MVC 6 中具有现有数据库的实体框架 7
【发布时间】:2015-12-31 19:27:57
【问题描述】:

您好,我在 Using Entity Framework 7 MVC 6 中从现有数据库中提取数据时遇到了一些问题。(我已发布项目代码 Here)。我已经使用正确的连接字符串设置了 appsettings.json:

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

我有我的自定义上下文:

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

两个 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; }
}

我正在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);
}

我的用户控制器:

[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();
    }
}

当我导航到用户/索引页面时,我在列表行上不断收到以下错误:

$exception {"对象引用未设置为对象的实例。"} System.NullReferenceException

由于某种原因,它没有从数据库中提取信息。我在 Microsoft SQLServer 2014 中创建它。用户表中有数据。我错过了一个步骤还是我试图以错误的方式访问数据?

【问题讨论】:

  • 尝试将[FromServices]添加到参数DatabaseContext。您可以使用public UsersController([FromServices] DatabaseContext context) 或仅将public IActionResult Index() 修改为public IActionResult Index([FromServices] DatabaseContext _context),而不使用属性_context。我不建议对属性使用[FromServices] 属性,因为该功能已在 RC2 中删除。如果你使用它,那么你应该删除显式设置_context 的构造函数。硒the answer
  • 如果我打开 URL http://localhost:14487/users/index/,则会收到错误 SqlException: Cannot open database "Demo" requested by the login。我可以看到构造函数public UsersController([FromServices] DatabaseContext context) 将在public IActionResult Index() 内部被成功调用,其中一个_context 不为空。
  • 能否在控制器的UsersControllerIndex 的控制器内部设置断点?您可以将启动 URL 从 http://localhost:14487/ 修改为 http://localhost:14487/users/index/ 或在启动程序后直接打开 URL。现在是_context 不是null 吗?如果你有一些错误,那是哪一个?我在尝试打开我没有打开的数据库Demo 时遇到错误(没有NullReferenceException 异常!)。我没有对程序进行任何修改。
  • 在修复了数据库视图CustomerInfoUserInfoVendorInfo 中的一些小写错误之后(使用Id 而不是id)并更改Username 的@987654355 属性@class to UserName 我得到了你描述的错误。我可以看到它将在 SQL 服务器上执行正确的 SQL select SELECT [u].[Id], [u].[Active], [u].[Created], [u].[EmailAddress], [u].[FirstName], [u].[LastName], [u].[Password], [u].[Updated], [u].[UserName] FROM [Users] AS [u],但在 EF 中出现错误。我现在新年有点忙,但我稍后会解决问题并发布我的答案。
  • 我忘了提到,如果您要使用dnx ef dbcontext scaffold ... 生成实体类,您应该在Bestro 项目中将"EntityFramework.Core": "7.0.0-rc1-final" 更改为"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final"

标签: c# asp.net-core-mvc entity-framework-core


【解决方案1】:

主要问题可以通过使用来解决

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

而不是

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

可以使用

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

但必须删除构造函数public UsersController(DatabaseContext context)。不推荐最后一种方式,因为RC2放弃了第二种方式。见the announcement

上述更改解决了您遇到的第一个问题,但您使用的数据库和测试数据产生了另一个问题,因为您的UsersCustomers 表的Updated 字段包含NULL 值。因此你必须使用

public DateTime? Updated { get; set; }

而不是

public DateTime Updated { get; set; }

我建议你的方式是使用表扬

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

您可以在主 project.json 所在的同一目录中执行(在src\JenSolo 中)。为了更好地阅读,我将部分命令包装在新行上。一个人应该把所有的事情放在一个原因上。上述命令将创建UsersCustomers 类而不是[Table("Users")]User[Table("Customers")]Customer,但您可以使用代码作为基础,并在以后手动进行所有需要的修改。

更新:在我看来,以下命令更好地对应于脚手架类的生成:

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

因为您在主项目 JenSolo 中使用 Class Library Bestro。您应该从命令行执行上述命令,并将文件夹...\src\JenSolo 作为当前目录。它将在类库项目 (Bestro) 中创建 Model 文件夹。 Model 文件夹将包含许多 *.cs 文件:每个数据库表一个文件和一个附加文件 DemoContext.cs,其中包含派生自 DbContext 的类 DemoContextDemo 是数据库的名称,您使用)。您应该从 DemoContext.cs 中删除 OnConfiguring 函数,以便能够通过配置连接字符串

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

在主项目JenSoloStartup.csConfigureServices中。

更新:从 .NET Core RC2 开始,应该使用 dotnet ef dbcontext scaffold 而不是 dnx ef dbcontext scaffold

【讨论】:

  • 非常感谢@Oleg 你似乎解决了这个问题。但是,我在让脚手架工作时遇到问题。以这样的方式工作会很好,我可以从 sqlserver 管理我的数据库并根据需要生成脚手架。
  • @Dblock247:不客气!您是否可以从现有的数据库表中生成类?你到底有什么问题?
  • 我无法生成任何内容。在包控制台中。我导航到 JenSolo 目录的根目录并尝试运行该命令,但出现以下错误。 nx :术语“dnx”未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确并重试。在 line:1 char:1 + dnx ef dbcontext scaffold + ~~~ + CategoryInfo : ObjectNotFound: (dnx:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException
  • @Dblock247:你应该打开命令提示符(cmd.exe),将目录更改为你的主项目JenSolo\src\JenSolo(该目录包含project.json,其中包含"commands": {"ef": "EntityFramework.Commands"}和@ 987654358@ 和 Data:DefaultConnection:ConnectionString) 并在目录中运行 dnx ef dbcontext scaffold ...--outputDir ..\Bestro\Model --verbose
  • 是的,我刚才在命令提示符下尝试过这个,它说 dnx 未被识别为内部或外部命令
猜你喜欢
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2016-09-07
  • 1970-01-01
  • 2014-04-23
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多