C# 实体框架 5 代码优先不创建数据库

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17601459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 09:59:41  来源:igfitidea点击:

Entity Framework 5 code-first not creating database

c#entity-frameworkasp.net-mvc-4ef-code-firstentity-framework-5

提问by Rob

I'm trying to create a new database using the code first concept of Entity Framework. However when running the code the database isn't created (using the DropCreateDatabaseIfModelChangessetting), though the code is running fine. I'm seeing the following exception when I try to get something from the database.

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

enter image description here

在此处输入图片说明

My project is setup using a separate DataAccesslayer with an generic service and repository construction. So all my entities, repository and also database context are in a separate project within the solution.

我的项目是使用DataAccess具有通用服务和存储库构建的单独层设置的。所以我的所有实体、存储库和数据库上下文都在解决方案中的一个单独项目中。

My global.asaxfile contains the following piece of code.

我的global.asax文件包含以下代码段。

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

This should initialise a new database if it isn't there, right?

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

My database context class looks like this;

我的数据库上下文类如下所示;

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

I've created this class following several tutorials and articles on the internet. It's all new to me, but as far as I can see everything seems correct so far. So now the two entities I'm using. They're called 'Project' and 'Portfolio'. They look like this;

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

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

And

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

The database I'm using is running on an external server, it came with the hosting provider I'm using. I've got a SQL Server database up and running and the connection string to the database is in the web.configof the website project. I've already tried removing the database and let the code recreate it, which unfortunately didn't work. Am I missing something obvious here? Or could it be a simple thing as access-rights to the server to create databases?

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

Note: When I run the Database-Update -Scriptcommand to generate SQL code, it seems that the correct SQL statements to create all tables are created.

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

UPDATE 1:Okay, thanks to some comments I came a bit further. I've added two properties to my entities to force some changes and I've also created an custom initializer like this;

更新 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);
        }
    }

I've also removed the initializer from the constructor of my context, so this mean i've remove this line of code;

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

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

After that i've added these three lines to my Global.asax file;

之后,我将这三行添加到我的 Global.asax 文件中;

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

When debugging i'm now getting this exception; enter image description here

调试时,我现在收到此异常; 在此处输入图片说明

This gives me the following information:

这给了我以下信息:

  • InnerException says: The provider didn't return a ProviderManifestToken
  • InnerException in the InnerException says: "For this operation an connection to the masterdatabase is required. A connection can't be made width the 'master'-database because the original connection is opened and the references has been removed from the connection. Please provide a non-open connection"
  • InnerException 说:提供者没有返回 ProviderManifestToken
  • InnerException 中的 InnerException 说:“对于此操作,需要连接到 masterdatabase。由于原始连接已打开且引用已从连接中删除,因此无法在 'master'-database 宽度上建立连接。请提供非开放连接”

After these action the database is inaccessible, so most likely deleted..

执行这些操作后,数据库将无法访问,因此很可能已删除..

What can possibly be done about this? It's most likely that I can't access the master database because my hostingprovider won't give me the proper access right ofcourse.

有什么办法可以解决这个问题?很可能我无法访问主数据库,因为我的托管服务提供商当然不会给我适当的访问权限。

采纳答案by Rob

Since no other solution came by I decided to change my approach.

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

I've first created the database myself and made sure the correct SQL user was configured and I had access.

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

Then I removed the initializer and the code from the Global.asax file. After that I ran the following command in the Package Manager Console (since the layered design I had to select the correct project in the console);

然后我从 Global.asax 文件中删除了初始化程序和代码。之后,我在包管理器控制台中运行以下命令(由于分层设计,我必须在控制台中选择正确的项目);

Enable-Migrations

After the migrations where enabled and I made some last minute changes to my entities I ran the command below to scaffold an new migration;

在启用迁移并在最后一刻对我的实体进行了一些更改后,我运行以下命令来构建新的迁移;

Add-Migration AddSortOrder

After my migrations were created I ran the following command in the console and voila, the database was updated with my entities;

创建迁移后,我在控制台中运行以下命令,瞧,数据库已更新为我的实体;

Update-Database -Verbose

To be able to seed the database when running the migration i've overridden the Seed method in my Configuraton.cs class, which was created when enabling the migrations. The final code in this method is like this;

为了能够在运行迁移时为数据库设置种子,我在启用迁移时创建的 Configuraton.cs 类中覆盖了 Seed 方法。这个方法的最终代码是这样的;

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

The disadvantage at the moment is that I have to manually migrate with (only) 2 commands in the package manager console. But the same time, the fact that this doesn't happen dynamically is also good because this prevents possibly inwanted changes to my database. Further everything works just perfect.

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

回答by RedAces

+1 for the detailed question.

详细问题+1。

Check that your connection string is pointing at the correct database and add the authorization attributes like this to access your database:

检查您的连接字符串是否指向正确的数据库并添加如下授权属性以访问您的数据库:

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

回答by Mohammad Ansari

befor intialize it run following code to create your database:

在初始化它之前运行以下代码来创建您的数据库:

context.Database.CreateIfNotExists();

context.Database.CreateIfNotExists();

回答by Sharad Tiwari

So First Remove the Db Name from the constructor parameter on context class and provide Db_name on the connection string and then try to rebuild your solution and run the application it will create Database for you application.

因此,首先从上下文类的构造函数参数中删除 Db 名称,并在连接字符串上提供 Db_name,然后尝试重建您的解决方案并运行应用程序,它将为您的应用程序创建数据库。

For Example :

例如 :

I am not passing the Db-Name on constructor parameter

我没有在构造函数参数上传递 Db-Name

public EmployeeContext()
            : base()
        {
            Database.SetInitializer<EmployeeContext>(new DropCreateDatabaseIfModelChanges<EmployeeContext>());
        }

and on the Connection string I am passing the Db-name like below.

在连接字符串上,我传递了如下所示的 Db 名称。

    <add name="EmployeeContext" connectionString="server=.; database=EFCodeFirstTPHInheritance; uid=sa;Password=crius@123;persistsecurityinfo=True" providerName="System.Data.SqlClient"/>
  </connectionStrings>