【问题标题】:Exception when code first tried to create database代码首次尝试创建数据库时出现异常
【发布时间】:2012-08-25 16:05:49
【问题描述】:

我创建了一个新的 ASP.NET MVC 4 应用程序,并希望它首先使用代码。但是,如果它不存在,它似乎最初不会创建数据库文件。如果我从 App_Data 文件夹中删除 .mdf 文件,那么当应用程序尝试访问数据库时会出现以下异常:

System.Data.SqlClient.SqlException: Cannot attach the file '<path-to-db-file>.mdf' as database '<my-db-file-name>'.

如果我在调试器的应用程序中运行它,那么我可以看到在调用 LazyInitializer.EnsureInitialized 时 InitializeSimpleMembershipAttribute::OnActionExecuting 方法中发生了异常。捕获的异常是:

[System.Reflection.TargetInvocationException]   {"Exception has been thrown by the target of an invocation."}   System.Reflection.TargetInvocationException

内部例外:

[System.InvalidOperationException]  {"The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588"} System.InvalidOperationException

然后有我上面提到的第一个异常作为它的内部异常。

任何想法我做错了什么?

更新

我刚刚尝试了一个全新的 MVC4 应用程序。我可以通过执行以下操作来复制它:

  1. 在 VS 向导中创建 MVC 应用程序。
  2. 第一次运行应用程序并进入登录页面(注意现在生成了 mdf 文件)。
  3. 删除mdf文件,返回登录页面。现在抛出异常。

【问题讨论】:

  • 你有想过这个问题吗?
  • @Eonasdan,一年后,是的。请看我的回答。

标签: c# asp.net-mvc entity-framework entity-framework-4 ef-code-first


【解决方案1】:

当我收到此错误时,为我解决的问题是我更改了 VS 项目的 App.config 文件中的连接字符串。

我已经在连接字符串中添加了这个:

  <connectionStrings>
<add name="Blog" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Integrated Security=true;AttachDbFileName=C:\Users\kostadin\Database1.mdf" providerName="System.Data.SqlClient" />

希望这对其他人有所帮助。

【讨论】:

    【解决方案2】:

    遇到了同样的问题并找到了我的解决方案here。 您所要做的就是通过打开 VS 开发人员命令提示符并输入(不带引号)来停止 LocalDb:

    “sqllocaldb.exe 停止 v11.0”

    “sqllocaldb.exe删除v11.0”

    下次 EF 将重新生成文件以及 db。

    【讨论】:

    • 你的链接帮助了我:)
    • LocalDB 实例可能有其他名称。运行 sqllocaldb info 将列出所有现有的 LocalDB 实例。
    【解决方案3】:

    如果您深入研究应用程序的 InitializeSimpleMembershipAttribute 类,您会看到它继承自 ActionFilterAttribute 类的以下重写方法:

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Ensure ASP.NET Simple Membership is initialized only once per app start
            LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
        }
    

    请注意该评论。应用程序每次运行都会检查一次,以确保简单成员资格已正确初始化。查看类顶部的私有变量:

        private static SimpleMembershipInitializer _initializer;
        private static object _initializerLock = new object();
        private static bool _isInitialized;
    

    它们都是静态的,并且都作为 refs 传递。对于您的情况,重要的是_isInitialized。 LazyInitializer.EnsureInitialized 所做的是检查_isInitialized 标志,如果它为假,则初始化它传递的引用目标,在本例中为SimpleMembershipInitializer 类型的_initializer。此时,它将标志设置为 true 并继续前进。如果LazyInitializer.EnsureInitialized 看到标志为真,它只会返回目标。由于该标志是一个静态变量,因此它在应用程序的整个生命周期内保持其值,这意味着在第一次初始化之后,EnsureInitialized 将始终简单地返回目标,即使数据库文件不再存在。换句话说,如果您在初始化后删除 .mdf 文件,应用程序将不知道,并且当应用程序尝试从数据库读取或写入时将引发异常。为了解决这个问题,您必须重新启动应用程序,这意味着如果您正在使用开发服务器,则终止开发服务器或在 IIS 中重新启动应用程序。

    这就是您面临的问题,但我怀疑许多遇到此问题的人都遇到了类似但不同的问题,他们在尝试登录时收到与此类似的错误消息:

    CREATE FILE 在尝试打开或创建物理文件“C:\path\to\your\project\App_Data\dbfile.mdf”时遇到操作系统错误 5(拒绝访问。)。 创建数据库失败。无法创建列出的某些文件名。检查相关错误。

    这很容易解决,我也会在这里快速介绍。

    默认情况下,Visual Studio 2012 使用称为 LocalDB 的简化版 SQL Server Express。 LocalDB 将启动应用程序的子进程,如果您在 Visual Studio 的开发服务器上运行您的应用程序(例如 http://localhost:[port] 显示在您的浏览器中),那么您正在运行这两个应用程序和 LocalDB 在您的用户帐户下,而不是在 SYSTEM 或 NETWORKSERVICE 下。解决此问题所需要做的就是为您的用户分配项目的 App_Data 文件夹的修改权限。再次尝试登录,应该会成功创建 .mdf 文件。

    如果你好奇,可以了解更多LocalDBhere.

    【讨论】:

    • 修改 App_Data 文件夹的权限解决了我的问题。我希望这对其他人有所帮助。
    【解决方案4】:

    您永远不应该在资源管理器中删除自动创建的 .mdf 文件,只能通过 SQL 管理工具或在对象资源管理器中删除。

    您遇到的问题(并且可以在您提供的步骤中复制)是数据库仍在 LocalDb 中注册。

    【讨论】:

    【解决方案5】:

    MVC 生成的代码使用名为“DefaultConnection”的数据库连接字符串。 如果您在 Web.config 中使用了不同的名称,则需要在以下位置引用该名称:

    1. InitializeSimpleMembershipAttribute.cs 中的InitializeSimpleMembershipAttribute.SimpleMembershipInitializer.ctor()。
    2. AccountModel.cs 中的 UsersContext.ctor()

    (或者只是在您的项目中搜索“DefaultConnection”)。

    【讨论】:

      【解决方案6】:

      您可以在项目根文件夹中 Global.asax 文件的 Application_Start 方法中处理 Code First 数据库初始化,如下所示:

          protected void Application_Start()
          {
              Database.SetInitializer<MyDBContext>(null);
          }
      

      如果您将 null 传递给 SetInitializer,它将不会创建或更改您的数据库表,您应该手动执行。

      数据库没有重新生成的原因是Application_Start在应用程序生命周期内只被触发一次。

      【讨论】:

      • 这不再是 MVC4 中的最佳实践。请改用 App_Start 文件夹中的类。
      【解决方案7】:

      您必须停止 IISExpress 实例并重新启动它(在 Visual Studio 中按 F5)。然后您将能够再次创建数据库。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-11
        • 1970-01-01
        • 2013-05-03
        • 1970-01-01
        • 2013-04-19
        相关资源
        最近更新 更多