Entity Framework 5 код-сначала не создается база данных
я пытаюсь создать новую базу данных, используя первую концепцию кода Entity Framework. Однако при запуске кода база данных не создается (используя DropCreateDatabaseIfModelChanges
setting), хотя код работает нормально. Я вижу следующее исключение, когда я пытаюсь сделать что-то из базы данных.
мой проект настроен с использованием отдельного 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>());
после этого я добавил Эти три строки в мой глобальный.файл asax;
Database.SetInitializer(new ForceDeleteInitializer());
MyContext c = new MyContext();
c.Database.Initialize(true);
при отладке я теперь получаю это исключение;
это дает мне следующую информацию:
- InnerException говорит: поставщик не вернулся ля ProviderManifestToken
- InnerException в InnerException говорит: "Для этой операции требуется подключение к базе данных masterdatabase. Связь не может быть сделал ширину "master" - базы данных, потому что исходное соединение открыт и ссылки были удалены из подключение. Просьба не открывать связи"
после этих действий база данных недоступна, поэтому, скорее всего, удалена..
что можно сделать это? Скорее всего, я не могу получить доступ к базе данных master, потому что мой hostingprovider не дает мне надлежащего права доступа.
4 ответов
поскольку другого решения не было, я решил изменить свой подход.
Я сначала создал базу данных сам и убедился, что правильный пользователь SQL был настроен, и у меня был доступ.
затем я удалил инициализатор и код из глобального.файл asax. После этого я запустил следующую команду в консоли диспетчера пакетов (так как многоуровневый дизайн мне пришлось выбрать правильный проект в консоли);
Enable-Migrations
после миграции, где включено и я в последнюю минуту внес некоторые изменения в свои сущности, я запустил команду ниже, чтобы создать новую миграцию;
Add-Migration AddSortOrder
после создания моих миграций я выполнил следующую команду в консоли и вуаля, база данных была обновлена с моими сущностями;
Update-Database -Verbose
чтобы иметь возможность заполнить базу данных при запуске миграции, я переопределил метод Seed в моей конфигурации.класс 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 для подробного вопроса.
убедитесь, что строка подключения указывает на правильную базу данных, и добавьте атрибуты авторизации для доступа к базе данных:
<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" />
befor intialize запустите следующий код для создания базы данных:
контексте.База данных.Операция createifnotexists();
поэтому сначала удалите имя БД из параметра конструктора в классе контекста и укажите 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>