MVC 3, MVCScaffolding. Использование SQLCe вместо Express. Файл базы данных не создан - PullRequest
0 голосов
/ 12 мая 2011

Я использовал новый 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) && ('\\' == 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 Ответ

0 голосов
/ 16 ноября 2011

Tom

У меня тоже были проблемы с Sql CE и Entity Framework. НО, возможно, я смогу объяснить пост, на который вы ссылаетесь, потому что теперь я в нем разбираюсь, поскольку пробился через него.

Для начала, эта запись в блоге была для пакета NuCet MVCScaffolding. Не уверен, что вы знаете, что делает этот пакет, но он в основном добавляет ссылку на Scaffolder, созданный Scott & Company для динамического генерирования CRUD для вас после того, как вы построили свои модели.

Насколько я понимаю, когда вы создаете модель, строите свой проект, вы можете запустить следующую команду в консоли диспетчера пакетов, и она создаст CRUD, о котором я упоминал выше.

Scaffold Controller [WhateverYourModelNameIs]

Теперь, когда этот процесс завершен, он генерирует класс Context для вашего приложения в папке Models. Если вы видите выше в своем коде (для SQLCEEntityFramework.cs) в методе Start, он упоминает, что вам нужно раскомментировать последнюю строку метода, чтобы он создал базу данных, если она не существует.

Наконец, после запуска приложения «база данных» SQL CE «должна» быть создана, и если вы щелкнете по папке App_Data и выберите «Показать все файлы» в верхней части обозревателя решений и нажмете значок «Обновить», вы должен увидеть вашу базу данных.

UPDATE

Извините, после проверки, Том, вы правы. Единственный способ создания базы данных - это выполнение одного из представлений, созданных Scaffolder.

...