How can I prevent my database from being recreated without seeding? - asp.net-mvc

I would like to prevent my program from dropping the database each time I run the debugger during the developing stage. I want to do this without the usual seeding the database. Since I will be using the Import and Export Data wizard, I would like to use this method of populating my database.
Is there a method to prevent the program from dropping the database?
Here's more information that I hope will help:
My Initializer
DropCreateDatabaseIfModelChanges<SchoolInDB>
{
protected override void Seed(SchoolInDB context)
{
context.Parents.Add(new Parent { Name = "Mary Lawson", Phone = "949-999-9999", Notes = "Please see IEP " });
base.Seed(context);
}
}
My application start
protected void Application_Start()
{
System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseAlways<SchoolIn.Models.SchoolInDB>());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
My DBContext
public class SchoolInDB : DbContext
{
public DbSet<Course> Courses { get; set; }
public DbSet<Teacher> Teachers { get; set; }
public DbSet<Parent> Parents { get; set; }
public DbSet<PdfReport> PdfReports { get; set; }
public DbSet<CourseProgress> CourseProgresses { get; set; }
public DbSet<ParentContact> ParentContacts { get; set; }
public DbSet<RedAlert> RedAlerts { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<Assignment> Assignments { get; set; }
}
My connection string
<connectionStrings>
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
I guess I want to avoid using the SetInitializer to DropCreateDatabaseAlways and just load the database whether the models changes or not. I'll be using the Import and Export Wizard to populate the database.
Thanks for helping!

I guess I want to avoid using the SetInitializer to DropCreateDatabaseAlways and just load the database whether the models changes or not. I'll be using the Import and Export Wizard to populate the database
So don't call SetInitializer. Just use the connection string to open the DB. BTW, DropCreateDatabaseIfModelChanges as the name implies, only drops/creates the DB when the schema changes.
That's how traditional DB first works.

To elaborate on RickAnd's answer, for future searchers looking for an answer.
I assume your full initializer class declaration is ..
public class ApplicationDbInitializer : DropCreateDatabaseAlways<SchoolInDB>
You simply need to replace this with...
public class ApplicationDbInitializer : CreateDatabaseIfNotExists<SchoolInDB>
That way your database will still be initialised with your seed values, but won't be dropped each time you start the application.

Related

Code migration unexpectedly tries to rename table

I want to implement a change log as advised in
Dev Express XAF T474899
I am using the security system generated by the XAF new solution wizard
I have defined some business objects to store the change log information.
One of these objects stores a link to the user
public virtual User User { get; set; }
On generating the code migration I am surprised to see the Up() method add the following
RenameTable(name: "dbo.UserRoles", newName: "RoleUsers");
DropPrimaryKey("dbo.RoleUsers");
AddPrimaryKey("dbo.RoleUsers", new[] { "Role_ID", "User_ID" });
On another occasion I found the following in an Up()
RenameTable(name: "dbo.EventResources", newName: "ResourceEvents");
// lots of other stuff
DropPrimaryKey("dbo.ResourceEvents");
AddPrimaryKey("dbo.ResourceEvents", new[] { "Resource_Key", "Event_ID" });
On both occasions the code that creates the entities is a Dev Express libary.
I have cross posted this question to Dev Express Support
The Dev Express business objects are defined in DevExpress.Persistent.BaseImpl.EF;
My DbContext context refers to them as
public DbSet<Role> Roles { get; set; }
public DbSet<User> Users { get; set; }
The meta data for Role shows
The meta data for User shows
My own business classes contain
namespace SBD.JobTalk.Module.BusinessObjects
{
[NavigationItem("Configuration")]
[DisplayName("Staff")]
[DefaultProperty("Summary")]
[ImageName("BO_Employee")]
[Table("Staff")]
public class Staff : BasicBo
{
public Staff()
{
Person = new Person();
}
public virtual Person Person { get; set; }
[StringLength(100, ErrorMessage = "The field cannot exceed 100 characters. ")]
[scds.Index("IX_Staff_UserName", 1, IsUnique = true)]
public string UserName { get; set; }
[NotMapped]
public string Summary => $"{Person.FirstName} {Person.LastName}";
//public virtual User User { get; set; }
}
}
public abstract class BasicBo : IXafEntityObject
{
[Browsable(false)]
[Key]
public virtual int Id { get; set; }
public virtual void OnCreated()
{
}
public virtual void OnSaving()
{
}
public virtual void OnLoaded()
{
}
}
If I un-comment the code to have the User property inside Staff, and generate a migration, the migration Up is
public override void Up()
{
RenameTable(name: "dbo.UserRoles", newName: "RoleUsers");
DropPrimaryKey("dbo.RoleUsers");
AddColumn("dbo.Staff", "User_ID", c => c.Int());
AddPrimaryKey("dbo.RoleUsers", new[] { "Role_ID", "User_ID" });
CreateIndex("dbo.Staff", "User_ID");
AddForeignKey("dbo.Staff", "User_ID", "dbo.Users", "ID");
}
[Update]
Interestingly there are more Dev Express tables than I first thought.
The primary keys are Identity.
I think am using Standard Authentication created before Dev Express added the Allow/Deny ability (V16.1)
[Update]
When I create a new project with the above settings, here is the DbContext.
using System;
using System.Data;
using System.Linq;
using System.Data.Entity;
using System.Data.Common;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.ComponentModel;
using DevExpress.ExpressApp.EF.Updating;
using DevExpress.Persistent.BaseImpl.EF;
using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy;
namespace XafApplication1.Module.BusinessObjects {
public class XafApplication1DbContext : DbContext {
public XafApplication1DbContext(String connectionString)
: base(connectionString) {
}
public XafApplication1DbContext(DbConnection connection)
: base(connection, false) {
}
public XafApplication1DbContext()
: base("name=ConnectionString") {
}
public DbSet<ModuleInfo> ModulesInfo { get; set; }
public DbSet<PermissionPolicyRole> Roles { get; set; }
public DbSet<PermissionPolicyTypePermissionObject> TypePermissionObjects { get; set; }
public DbSet<PermissionPolicyUser> Users { get; set; }
public DbSet<ModelDifference> ModelDifferences { get; set; }
public DbSet<ModelDifferenceAspect> ModelDifferenceAspects { get; set; }
}
}
OK, I will take a stab :) Your Up() code is trying to rename the table UserRoles to RoleUsers. This means you have a prior migration where UserRoles was the table name - probably from your DevEx stuff. This could happen if they changed their models in an upgrade. The current models are expecting RoleUsers etc. so you need to get there.
So first option is let the migration do the renaming to match the underlying model. I assume this didn't work or causes other issues?
You might be able to 'fool' entity framework into using the old tables with fluent code or annotations, but if it has new columns or relationships that won't work.
What I would do is this:
1) Create a new test project with the same references you had and
copy your context and DbSets. Point the connection string to a
new database.
2) Add a migration and script it out:
update-database -Script.
3) Examine this script a use it to create
the objects needed in your database. Migrate data from the old
tables to new if needed.
4) Remove the old tables
5) In your actual
project add a migration to resync your models:
add-migration SyncDevExUpdate -IgnoreChange, update-database
Now you will have the tables your models expect.

Updating Multiple Databases MVC 5

I have two contexts working with visual studio 2013. The one for the IdentityModel and another context I created for the main database. The problem I am having is whenever I run the update-database in the package manager console, it creates the ApplicationDBContext DB in both. The one for my main database never gets created because it seems it sees it as the ApplicationDBContext. I have tried Enable-Migrations -ContextTypeName DI_MVC.Models.DIDBContext and it does not create the main database tables for the DIDBContext class. I was able to do this in visual studio 2012 without an issue in creating the database. That was without the ApplicationDBContext though. Any help on what I am doing wrong would be greatly appreciated.
Below are my 2 code files. The normal IdentityModel and my DIDBContext class I created. Also I will display the web.config file as well with the database connections. There are 2 .mdf files that get created within the App_Data folder but both databases contain the membership tables.
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace DI_MVC.Models
{
public class DIDBContext : DbContext
{
public DIDBContext()
: base("DIDBContext")
{
}
public DbSet<DI_ConnectionStrings_CSI> CSIs { get; set; }
public DbSet<DI_DropDownValues_DDV> DDVs { get; set; }
public DbSet<DI_Types_DIT> DITs { get; set; }
public DbSet<DI_FORM_DIF> DIFs { get; set; }
public DbSet<DI_FormTabs_DFT> DFTs { get; set; }
public DbSet<DFI_FormSections_DFS> DFSs { get; set; }
public DbSet<DI_FormElements_DFE> DFEs { get; set; }
public DbSet<DI_DFE_DFS_DDD> DDDs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DI_DFE_DFS_DDD>().HasKey(k => new { k.DDD_DFS_ID, k.DDD_DFE_ID });
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace DI_MVC.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public DateTime BirthDate { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
}
}
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-DI_MVC-meohmeohmy.mdf;Initial Catalog=aspnet-DI_MVC-meohmeohmy;Integrated Security=True"
providerName="System.Data.SqlClient" />
<add name="DIDBContext" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-DI_MVC-MainDB.mdf;Initial Catalog=aspnet-DI_MVC-MainDB;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
You're not alone. It would make sense that if you enabled migrations for a single DbContext it would only update the DbContext that migrations are enabled for or at least let you specify which DbContext you wanted to update. However, that is not the case.
Read - this and this.
TLDR Enable-Migrations –EnableAutomaticMigrations

Questions about Metadata

Wanted to get some clarity on something in regards to how we are implementing our Metadata.
Our Breeze Api is not directly tied to SQL Server so we have implemented a custom EFContextProvider and the DbSet below....
public class MetadataDbContext : DbContext
{
public MetadataDbContext()
: base(nameOrConnectionString: "MetadataDb")
{
Database.SetInitializer<MetadataDbContext>(null);
}
public DbSet<Order> Orders { get; set; }
public DbSet<OrderMeter> OrderMeters { get; set; }
public DbSet<OrderDemand> OrderDemand { get; set; }
public DbSet<MeterHistory> MeterHistory { get; set; }
public DbSet<FieldTech> FieldTechs { get; set; }
public DbSet<Dispatcher> Dispatchers { get; set; }
public DbSet<OrderLookupData> LookupData { get; set; }
public DbSet<Organization> Organizations { get; set; }
public DbSet<Location> Locations { get; set; }
public DbSet<Alert> Alert { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
As you can see I am pointing that DbSet at a database called "MetadataDb" which is just an sdf file we deploy with our project. We then override SaveChangesCore in the Context Provider to route our saves to the correct services instead of going direct to Entity Framework. My question is during some testing we noticed that it seemed Breeze was trying to update the sdf file in some cases. It did not appear that the size of the file changed, but just wanted to make sure before we go to production that the sdf file we are pointing the Metadata at does not grow on our server.
Thanks really enjoy using Breeze.
If the only thing that you are using the .sdf file for is to return metadata then Breeze doesn't do anything more than extract the "edmx" from the ObjectContext or DbContext associated with your database. My guess is that just the act of spinning up the context is causing EF to "modify" the "sdf" file. Breeze is not doing anything to touch the database directly.

How to persist old data in database while using EF Data Migrations

I was thinking that the purpose of EF DataMigrations is to preserve old data while changing the database structure. Do I think right? But when I update the database with migrations all the old data is erased.
Do I make something wrong or maybe it isn't possible to use data migrations in this kind of scenario ?
this is DbContext:
public class CodeFirstContext : DbContext
{
public CodeFirstContext() : base ("ZenRandevuIzle")
{
}
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<Takvim> Takvims { get; set; }
public DbSet<Musteri> Musteris { get; set; }
public DbSet<Randevu> Randevus { get; set; }
public DbSet<SeansTuru> SeansTurus { get; set; }
public DbSet<Hizmet> Hizmets { get; set; }
public DbSet<Islem> Islems { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
}
}
this is Global.asax:
Database.SetInitializer<CodeFirstContext>(new CodeFirstContextInit());
this is migration Config:
internal sealed class Configuration : DbMigrationsConfiguration<CodeFirstContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
Does the CodeFirstContextInit initialiser drop the database and recreate it (what is its base class?) normally I wouldn't have an initializer when using migrations.
To use EF 4.3 Code First Data Migrations with an existing database you need to create an "empty" migration so that the Migration-History table is created and a baseline can be established.
The Steps outlined in this post should help http://thedatafarm.com/data-access/using-ef-4-3-code-first-migrations-with-an-existing-database

Mapping EF 4.1 code-first models to database tables

I have been trying the model-first method when designing my application. We usually like to add a prefix to our tables in larger databases so it is easier to find stuff. For example:
sc_ = Shopping cart tables
wb_ = Water billing tables
ea_ = Employment Application tables
The class I have setup looks like this so far.
public class EFDbContext : DbContext
{
public DbSet<Transaction> Transactions { get; set; }
public DbSet<TransactionItem> TransactionItems { get; set; }
public DbSet<Response> Response { get; set; }
}
Web.config (set currently for local database testing):
<add name="EFDbContext" connectionString="Data Source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=database" providerName="System.Data.SqlClient"/>
What do I need to change so that the Transaction object gets linked to the sc_Transactions table? I haven't seen in my searching that clarifies this.
As a second question, do I have to manually create my tables?
You can override the OnModelCreating method from DbContext in your EFDbContext class:
public class EFDbContext : DbContext
{
public DbSet<Transaction> Transactions { get; set; }
public DbSet<TransactionItem> TransactionItems { get; set; }
public DbSet<Response> Response { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Transaction>().MapSingleType().ToTable("someTableNameHere");
}
}
See this post for more info.
You can use System.ComponentModel.DataAnnotations like so:
[Table("tblUser")]
public class User
{
public int ID { get; set; }
public string Name { get; set; }
}
Or with EF 4 you can override the OnModelCreating method to map your tables, which is quite powerful thing as you can map and adjust many things at once.
public class MyContext: DbContext
{
DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().MapSingleType().ToTable("tblUser");
}
}
For more info see:
EF4 CF custom database mapping
EF keynotes from the Build2011 event (custom mappings are at about
15 min or so)

Resources