22

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 DropCreateDatabaseIfModelChanges setting), though the code is running fine. I'm seeing the following exception when I try to get something from the database.

enter image description here

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

My global.asax file contains the following piece of code.

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.config of 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?

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

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;

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;

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"

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.

4

4 回答 4

14

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

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

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

Enable-Migrations

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

Add-Migration AddSortOrder

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

Update-Database -Verbose

为了能够在运行迁移时为数据库播种,我覆盖了我的 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;
    }
}

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

于 2013-07-30T10:42:04.587 回答
2

+1 详细问题。

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

<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" />
于 2013-07-11T19:33:18.940 回答
0

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

例如 :

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

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

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

    <add name="EmployeeContext" connectionString="server=.; database=EFCodeFirstTPHInheritance; uid=sa;Password=crius@123;persistsecurityinfo=True" providerName="System.Data.SqlClient"/>
  </connectionStrings> 
于 2018-08-21T17:49:23.723 回答
0

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

context.Database.CreateIfNotExists();

于 2017-09-30T08:01:26.897 回答