#asp.net #asp.net-mvc-3 #sql-server-ce-4
#asp.net #asp.net-mvc-3 #sql-server-ce-4
Вопрос:
Я использую новый MVCScaffolding
для моей следующей CMS, и до сих пор это было потрясающе. Потрясающе, пока я не захотел сменить свою базу данных по SQLExpress
умолчанию на SQLCe
локальную базу данных.
Здесь ( http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/ ) в нем говорится, что если я установлю пакет « EFCodeFirst.SqlServerCompact
«, он позаботится о его изменении и даже о создании файла базы данных. Итак, я это сделал.
Был создан файл с именем « SQLCEEntityFramework.cs
«, в этом файле были некоторые ошибки. Например, ссылка на « System.Data.Entity.Database
«, которая больше не существует, и ссылки на DbDatabase
которая Database
существует сейчас. Итак, я исправил эти ошибки и запустил приложение.
Все работает как обычно, но в мой Web.config
каталог не добавляется строка подключения, и в моем App_Data
каталоге не создается файл базы данных. Итак, теперь я начинаю задаваться вопросом, не делаю ли я что-то неправильно…
Кто-нибудь имеет представление о том, что здесь происходит и как это исправить?
БОЛЬШОЕ спасибо.
РЕДАКТИРОВАТЬ: На всякий случай, если вы хотите посмотреть, что находится в файле SQLCEEntityFramework.cs :
using System;
using System.Data.Entity;
using System.Data.SqlServerCe;
using System.IO;
using System.Transactions;
using System.Data.Entity.Infrastructure;
[assembly: WebActivator.PreApplicationStartMethod(typeof(CMS.App_Start.SQLCEEntityFramework), "Start")]
namespace CMS.App_Start {
public static class SQLCEEntityFramework {
public static void Start() {
Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
// Sets the default database initialization code for working with Sql Server Compact databases
// Uncomment this line and replace CONTEXT_NAME with the name of your DbContext if you are
// using your DbContext to create and manage your database
//DbDatabase.SetInitializer(new CreateCeDatabaseIfNotExists<CONTEXT_NAME>());
}
}
public abstract class SqlCeInitializer<T> : IDatabaseInitializer<T> where T : DbContext {
public abstract void InitializeDatabase(T context);
#region Helpers
/// <summary>
/// Returns a new DbContext with the same SqlCe connection string, but with the |DataDirectory| expanded
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
protected static DbContext ReplaceSqlCeConnection(DbContext context) {
if (context.Database.Connection is SqlCeConnection) {
SqlCeConnectionStringBuilder builder = new SqlCeConnectionStringBuilder(context.Database.Connection.ConnectionString);
if (!String.IsNullOrWhiteSpace(builder.DataSource)) {
builder.DataSource = ReplaceDataDirectory(builder.DataSource);
return new DbContext(builder.ConnectionString);
}
}
return context;
}
private static string ReplaceDataDirectory(string inputString) {
string str = inputString.Trim();
if (string.IsNullOrEmpty(inputString) || !inputString.StartsWith("|DataDirectory|", StringComparison.InvariantCultureIgnoreCase)) {
return str;
}
string data = AppDomain.CurrentDomain.GetData("DataDirectory") as string;
if (string.IsNullOrEmpty(data)) {
data = AppDomain.CurrentDomain.BaseDirectory ?? Environment.CurrentDirectory;
}
if (string.IsNullOrEmpty(data)) {
data = string.Empty;
}
int length = "|DataDirectory|".Length;
if ((inputString.Length > "|DataDirectory|".Length) amp;amp; ('\' == inputString["|DataDirectory|".Length])) {
length ;
}
return Path.Combine(data, inputString.Substring(length));
}
#endregion
}
/// <summary>
/// An implementation of IDatabaseInitializer that will recreate and optionally re-seed the
/// database only if the database does not exist.
/// To seed the database, create a derived class and override the Seed method.
/// </summary>
/// <typeparam name="TContext">The type of the context.</typeparam>
public class CreateCeDatabaseIfNotExists<TContext> : SqlCeInitializer<TContext> where TContext : DbContext {
#region Strategy implementation
public override void InitializeDatabase(TContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
var replacedContext = ReplaceSqlCeConnection(context);
bool databaseExists;
using (new TransactionScope(TransactionScopeOption.Suppress)) {
databaseExists = replacedContext.Database.Exists();
}
if (databaseExists) {
// If there is no metadata either in the model or in the databaase, then
// we assume that the database matches the model because the common cases for
// these scenarios are database/model first and/or an existing database.
if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false)) {
throw new InvalidOperationException(string.Format("The model backing the '{0}' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.", context.GetType().Name));
}
}
else {
context.Database.Create();
Seed(context);
context.SaveChanges();
}
}
#endregion
#region Seeding methods
/// <summary>
/// A that should be overridden to actually add data to the context for seeding.
/// The default implementation does nothing.
/// </summary>
/// <param name="context">The context to seed.</param>
protected virtual void Seed(TContext context) {
}
#endregion
}
/// <summary>
/// An implementation of IDatabaseInitializer that will <b>DELETE</b>, recreate, and optionally re-seed the
/// database only if the model has changed since the database was created. This is achieved by writing a
/// hash of the store model to the database when it is created and then comparing that hash with one
/// generated from the current model.
/// To seed the database, create a derived class and override the Seed method.
/// </summary>
public class DropCreateCeDatabaseIfModelChanges<TContext> : SqlCeInitializer<TContext> where TContext : DbContext {
#region Strategy implementation
/// <summary>
/// Executes the strategy to initialize the database for the given context.
/// </summary>
/// <param name="context">The context.</param>
public override void InitializeDatabase(TContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
var replacedContext = ReplaceSqlCeConnection(context);
bool databaseExists;
using (new TransactionScope(TransactionScopeOption.Suppress)) {
databaseExists = replacedContext.Database.Exists();
}
if (databaseExists) {
if (context.Database.CompatibleWithModel(throwIfNoMetadata: true)) {
return;
}
replacedContext.Database.Delete();
}
// Database didn't exist or we deleted it, so we now create it again.
context.Database.Create();
Seed(context);
context.SaveChanges();
}
#endregion
#region Seeding methods
/// <summary>
/// A that should be overridden to actually add data to the context for seeding.
/// The default implementation does nothing.
/// </summary>
/// <param name="context">The context to seed.</param>
protected virtual void Seed(TContext context) {
}
#endregion
}
/// <summary>
/// An implementation of IDatabaseInitializer that will always recreate and optionally re-seed the
/// database the first time that a context is used in the app domain.
/// To seed the database, create a derived class and override the Seed method.
/// </summary>
/// <typeparam name="TContext">The type of the context.</typeparam>
public class DropCreateCeDatabaseAlways<TContext> : SqlCeInitializer<TContext> where TContext : DbContext {
#region Strategy implementation
/// <summary>
/// Executes the strategy to initialize the database for the given context.
/// </summary>
/// <param name="context">The context.</param>
public override void InitializeDatabase(TContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
var replacedContext = ReplaceSqlCeConnection(context);
if (replacedContext.Database.Exists()) {
replacedContext.Database.Delete();
}
context.Database.Create();
Seed(context);
context.SaveChanges();
}
#endregion
#region Seeding methods
/// <summary>
/// A that should be overridden to actually add data to the context for seeding.
/// The default implementation does nothing.
/// </summary>
/// <param name="context">The context to seed.</param>
protected virtual void Seed(TContext context) {
}
#endregion
}
}
Ответ №1:
Том,
У меня тоже возникли проблемы с Sql CE и Entity Framework. НО, возможно, я смогу объяснить сообщение, на которое вы ссылаетесь, потому что я разбираюсь в его использовании теперь, когда я пробился через это.
Для начала, эта запись в блоге была для пакета NuGet MvcScaffolding. Не уверен, знаете ли вы, что делает этот пакет, но он в основном добавляет ссылку на каркас, созданный Scott amp; Company для динамической генерации CRUD для вас, как только вы построите свои модели.
Насколько я понимаю, после создания модели, сборки вашего проекта вы можете запустить следующую команду в консоли диспетчера пакетов, и она создаст CRUD, о котором я упоминал выше.
Scaffold Controller [WhateverYourModelNameIs]
Теперь, когда этот процесс завершен, он генерирует класс контекста для вашего приложения в папке Models. Если вы видите выше в своем коде (для SQLCEEntityFramework.cs) в методе Start, там упоминается, что вам нужно раскомментировать последнюю строку метода, чтобы он создал базу данных, если она не существует.
Наконец, как только вы запустите свое приложение, база данных SQL CE «должна» быть создана, и если вы нажмете на папку App_Data и выберете «Показать все файлы» в верхней части обозревателя решений и нажмете значок обновления, вы должны увидеть свою базу данных.
Обновить:
Извините, после тестирования этого, Том, вы правы. База данных создается только в том случае, если вы выполняете одно из представлений, созданных каркасом.