我正在尝试使用Entity Framework的代码优先概念创建一个新数据库。但是,在运行代码时,不会创建数据库(使用DropCreateDatabaseIfModelChanges
设置),尽管代码运行正常。当我尝试从数据库中获取内容时,我看到以下异常。
我的项目使用单独的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语句。
更新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>());
之后我将这三行添加到我的Global.asax文件中;
Database.SetInitializer(new ForceDeleteInitializer());
MyContext c = new MyContext();
c.Database.Initialize(true);
调试时我现在得到这个例外;
这给了我以下信息:
执行这些操作后,数据库无法访问,因此很可能已删除..
对此可以做些什么?我很可能无法访问master数据库,因为我的hostingprovider不会给我正确的访问权限。
答案 0 :(得分:13)
由于没有其他解决方案,我决定改变我的方法。
我自己首先创建了数据库并确保配置了正确的SQL用户并且我有权访问。
然后我从Global.asax文件中删除了初始化程序和代码。之后我在Package Manager控制台中运行了以下命令(因为分层设计我必须在控制台中选择正确的项目);
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个命令手动迁移。但同时,这不会动态发生的事实也很好,因为这可以防止对我的数据库进行有害的更改。此外,一切都很完美。
答案 1 :(得分:1)
+1详细问题。
检查您的连接字符串是否指向正确的数据库,并添加这样的授权属性以访问您的数据库:
<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" />
答案 2 :(得分:0)
初始化它运行以下代码来创建数据库:
context.Database.CreateIfNotExists();
答案 3 :(得分:0)
因此,首先从上下文类的构造函数参数中删除Db名称,并在连接字符串上提供Db_name,然后尝试重建您的解决方案并运行该应用程序,它将为您的应用程序创建数据库。
例如:
我没有在构造函数参数上传递Db-Name
public EmployeeContext()
: base()
{
Database.SetInitializer<EmployeeContext>(new DropCreateDatabaseIfModelChanges<EmployeeContext>());
}
,然后在Connection字符串上传递如下的Db名称。
<add name="EmployeeContext" connectionString="server=.; database=EFCodeFirstTPHInheritance; uid=sa;Password=crius@123;persistsecurityinfo=True" providerName="System.Data.SqlClient"/>
</connectionStrings>