MVC 3, MVCScaffolding. Using SQLCe instead of Express. No database file created
I've been using the new MVCScaffolding
for my next CMS and it's been awesome so far. Awesome until I wanted to change my SQLExpress
default database to a SQLCe
local database.
Here ( http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/ ) it says that if I install the "EFCodeFirst.SqlServerCompact
" package it'll take care of changing it and even creating the database file. So I did it.
It created a file called "SQLCEEntityFramework.cs
", in that file there was some errors. Like a reference to "System.Data.Entity.Database
" which does not exist anymore and references to DbDatabase
which is Database
now. So I fixed those errors and ran the application.
Everything is running as usual, but no connection string gets added to my Web.config
and no database file gets created in my App_Data
directory. So now I'm starting to wonder if I'm doing something wrong...
Anybody has any clue of what is happening here and how to fix it?
Thanks a LOT.
EDIT: Just in case you want to see what's in the SQLCEEntityFramework.cs file :
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;
}
开发者_如何学C 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
}
}
Tom,
I too have been experiencing issues with Sql CE and the Entity Framework. BUT, I may be able to explain the post that you are referencing because I am versed in using it now that I have fought my way through it.
For starters, that blog entry was for the MVCScaffolding NuGet package. Not sure if you know what this package does but it basically adds a reference to the Scaffolder that Scott & Company created to dynamically generate CRUD for you once you have built your models.
My understanding is that once you create a model, build your project, you can run the following command in the Package Manager Console and it will create the CRUD that I mentioned above.
Scaffold Controller [WhateverYourModelNameIs]
Now, once this process is complete, it generates a Context class for your application under the Models folder. If you see above in your code (for SQLCEEntityFramework.cs) in the Start method, it mentions that you need to uncomment the last line of the method in order for it to create the db if it does not exist.
Lastly, once you execute your application, a SQL CE database "should" be created and if you click on the App_Data folder and choose to 'Show All Files' at the top of the Solution Explorer and hit the Refresh icon, you should see your database.
UPDATE:
So sorry, after testing this, Tom, you are correct. Only way the database is created is if you execute one of the views that were created by the Scaffolder.
精彩评论