20

我试图创建一个新的数据库使用实体框架的代码第一个概念。但是,运行代码时,不会创建数据库(使用DropCreateDatabaseIfModelChanges设置),尽管代码运行良好。当我尝试从数据库中获取某些内容时,发现以下异常。实体框架5代码优先不创建数据库

enter image description here

我的项目是使用一个单独的DataAccess层与通用服务和资源库建设安装。所以我所有的实体,存储库和数据库上下文都在解决方案中的一个单独项目中。我的global.asax文件包含以下代码段。

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>()); 

这应该初始化一个新的数据库,如果它不存在,对吗?

我的数据库上下文类看起来像这样;

namespace Website.DAL.Model 
{ 
    public class MyContext : DbContext 
    { 
     public IDbSet<Project> Projects { get; set; } 
     public IDbSet<Portfolio> Portfolios { get; set; } 

     /// <summary> 
     /// The constructor, we provide the connectionstring to be used to it's base class. 
     /// </summary> 
     public MyContext() 
      : base("MyConnectionString") 
     { 
     } 

     static MyContext() 
     { 
      try 
      { 
       Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>()); 
      } 
      catch (Exception) 
      { 
       throw; 
      } 
     } 

     /// <summary> 
     /// This method prevents the plurarization of table names 
     /// </summary> 
     /// <param name="modelBuilder"></param> 
     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      base.OnModelCreating(modelBuilder); 
      modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>(); 
     } 
    } 
} 

我在互联网上的几个教程和文章后创建了这个类。这对我来说都是新的,但据我所知,一切似乎都是正确的。所以现在我正在使用的两个实体。他们被称为'项目'和'投资组合'。他们看起来像这样;

public class Portfolio 
    { 
     [Key] 
     public Guid Id { get; set; } 
     public String Name { get; set; } 
     public DateTime StartDate { get; set; } 
     public DateTime? EndDate { get; set; } 
     public bool IsPublished { get; set; } 

     public virtual ICollection<Project> Projects { get; set; } 
    } 

而且

public class Project 
    { 
     [Key] 
     public Guid Id { get; set; } 
     public DateTime StartDate { get; set; } 
     public DateTime? EndDate { get; set; } 
     public bool IsPublished { get; set; } 
     public String Title { get; set; } 
    } 

我使用一个外部服务器上运行的数据库,它带着我使用了托管服务提供商。我已经启动了一个SQL Server数据库,并且该数据库的连接字符串位于网站项目的web.config中。我已经尝试删除数据库,并让代码重新创建它,但不幸的是没有工作。我在这里错过了很明显的东西吗或者它可能是一个简单的东西,作为创建数据库的服务器的访问权限?

注:当我运行Database-Update -Script命令生成SQL代码,它似乎是正确的SQL语句来创建创建的所有表。

UPDATE 1: 好的,多亏了一些评论,我来得更进一步。我已经为我的实体添加了两个属性来强制进行一些更改,并且我还创建了一个像这样的自定义初始化程序;

public class ForceDeleteInitializer : IDatabaseInitializer<MyContext> 
    { 
     private readonly IDatabaseInitializer<MyContext> _initializer = new DropCreateDatabaseIfModelChanges<MyContext>(); 

     public ForceDeleteInitializer() 
     { 
      //_initializer = new ForceDeleteInitializer(); 
     } 

     public void InitializeDatabase(MyContext context) 
     { 
      //This command is added to prevent open connections. See http://stackoverflow.com/questions/5288996/database-in-use-error-with-entity-framework-4-code-first 
      context.Database.ExecuteSqlCommand("ALTER DATABASE borloOntwikkel SET SINGLE_USER WITH ROLLBACK IMMEDIATE"); 
      _initializer.InitializeDatabase(context); 
     } 
    } 

我也从我的上下文的构造函数中删除了初始化器,所以这意味着我已经删除了这行代码;

Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>()); 

之后,我已经将这三行添加到我的全球。asax文件;

Database.SetInitializer(new ForceDeleteInitializer()); 
MyContext c = new MyContext(); 
c.Database.Initialize(true); 

当调试我现在得到这个异常; enter image description here

这给了我以下信息:

  • 的InnerException说:提供程序未返回在InnerException一个 ProviderManifestToken
  • 的InnerException说:“对于这种操作方式的连接masterdatabase是必需的。连接不能为 因为原来的连接是 已打开并且已从连接中删除引用而使宽度为'主'数据库。请提供非开放连接”

这些动作后无法访问数据库,所以最有可能被删除..

什么都不可能了解这一点呢?这很可能是我无法访问master数据库,因为我的主机提供商不会给我正确的访问权限。

+0

代码和配置看起来确定,你可能停留在托管情况。 EF想要创建一个带有特殊帮助表的Db(1或2个哈希)。也许你可以从本地Db编写脚本并将其移至托管的Db? –

+0

运行代码的用户帐户是否具有删除和创建数据库的必要权限? – jlew

+0

@亨克,我刚刚尝试运行生成的SQL脚本。它用一条记录为我创建了一个__MigrationHistory表。我还通过添加'this.Database.Initialize(true)'行来修改我的上下文的构造函数。这并没有给我一个错误,但也没有创建任何表。然后我从MigrationHistory表中删除记录,并再次发生同样的错误。所以我会尝试在本地数据库上运行它,看看会发生什么。 – Rob

回答

12

由于没有其他的解决方案来过我决定改变我的做法。

我自己首先创建了数据库,并确保正确的SQL用户已配置,并且有权访问。

然后我从Global.asax文件中删除了初始值设定项和代码。之后,我在包管理器控制台中运行了以下命令(因为分层设计我不得不在控制台中选择正确的项目);

Enable-Migrations 

在迁移后能在那里和我做了一些最后一分钟改变我的实体,我跑下面的命令来脚手架的新移民;

Add-Migration AddSortOrder 

我的迁移创建后,我在控制台运行下面的命令,瞧,数据库是用我的实体更新;

Update-Database -Verbose 

为了能够运行迁移我已经覆盖了种子法在我Configuraton.cs类,这是使迁移时创建,当种子数据库。这种方法的最终代码就是这样的;

protected override void Seed(MyContext context) 
     { 
      // This method will be called after migrating to the latest version. 

      //Add menu items and pages 
      if (!context.Menu.Any() && !context.Page.Any()) 
      { 
       context.Menu.AddOrUpdate(new Menu() 
              { 
               Id = Guid.NewGuid(), 
               Name = "MainMenu", 
               Description = "Some menu", 
               IsDeleted = false, 
               IsPublished = true, 
               PublishStart = DateTime.Now, 
               LastModified = DateTime.Now, 
               PublishEnd = null, 
               MenuItems = new List<MenuItem>() 
                   { 
                    new MenuItem() 
                     { 
                      Id = Guid.NewGuid(), 
                      IsDeleted = false, 
                      IsPublished = true, 
                      PublishStart = DateTime.Now, 
                      LastModified = DateTime.Now, 
                      PublishEnd = null, 
                      Name = "Some menuitem", 
                      Page = new Page() 
                         { 
                          Id = Guid.NewGuid(), 
                          ActionName = "Some Action", 
                          ControllerName = "SomeController", 
                          IsPublished = true, 
                          IsDeleted = false, 
                          PublishStart = DateTime.Now, 
                          LastModified = DateTime.Now, 
                          PublishEnd = null, 
                          Title = "Some Page" 
                         } 
                     }, 
                    new MenuItem() 
                     { 
                      Id = Guid.NewGuid(), 
                      IsDeleted = false, 
                      IsPublished = true, 
                      PublishStart = DateTime.Now, 
                      LastModified = DateTime.Now, 
                      PublishEnd = null, 
                      Name = "Some MenuItem", 
                      Page = new Page() 
                         { 
                          Id = Guid.NewGuid(), 
                          ActionName = "Some Action", 
                          ControllerName = "SomeController", 
                          IsPublished = true, 
                          IsDeleted = false, 
                          PublishStart = DateTime.Now, 
                          LastModified = DateTime.Now, 
                          PublishEnd = null, 
                          Title = "Some Page" 
                         } 
                     } 
                   } 
              }); 
      } 

      if (!context.ComponentType.Any()) 
      { 
       context.ComponentType.AddOrUpdate(new ComponentType() 
       { 
        Id = Guid.NewGuid(), 
        IsDeleted = false, 
        IsPublished = true, 
        LastModified = DateTime.Now, 
        Name = "MyComponent", 
        PublishEnd = null, 
        PublishStart = DateTime.Now 
       }); 
      } 


      try 
      { 
       // Your code... 
       // Could also be before try if you know the exception occurs in SaveChanges 

       context.SaveChanges(); 
      } 
      catch (DbEntityValidationException e) 
      { 
       //foreach (var eve in e.EntityValidationErrors) 
       //{ 
       // Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", 
       //  eve.Entry.Entity.GetType().Name, eve.Entry.State); 
       // foreach (var ve in eve.ValidationErrors) 
       // { 
       //  Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", 
       //   ve.PropertyName, ve.ErrorMessage); 
       // } 
       //} 
       //throw; 

       var outputLines = new List<string>(); 
       foreach (var eve in e.EntityValidationErrors) 
       { 
        outputLines.Add(string.Format(
         "{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:", 
         DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State)); 
        foreach (var ve in eve.ValidationErrors) 
        { 
         outputLines.Add(string.Format(
          "- Property: \"{0}\", Error: \"{1}\"", 
          ve.PropertyName, ve.ErrorMessage)); 
        } 
       } 
       System.IO.File.AppendAllLines(@"c:\temp\errors.txt", outputLines); 
       throw; 
      } 
     } 

目前的缺点是我必须在包管理器控制台中手动迁移(仅)2个命令。但是同时,这种情况不会动态发生也是很好的,因为这样可以防止对我的数据库进行可能不需要的更改。进一步的一切都很完美。

1

+1的详细问题。

检查您的连接字符串是在正确的数据库指向,并添加授权属性这样来访问数据库:

<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" /> 
0

befor intialize它运行下面的代码来创建数据库:

context.Database.CreateIfNotExists();

相关问题