SQL Server CE Code First migrations problems - c#

I have a bunch of problems trying to enable (code-first) migrations for my SQL Server Compact 4.0 database for my desktop .NET app.
Enable-Migrations does work and the directory Migrations is created. After that when I try to run Add-Migration InitialMigration, I get:
Access to the database file is not allowed. [ 1914,File name = Logo.sdf,SeCreateFile ]
This is the first problem, but I solved it by running Visual Studio as Administrator... don't like that solution and also don't know if later in production it will work without the app being run in Admin mode. I let that problem aside for now...
My connection string:
<add name="LogoContext"
connectionString="Data Source=Logo.sdf"
providerName="System.Data.SqlServerCE.4.0"/>`
So after running Add-Migration InitialMigration in Administrator mode I get an empty migration... that's ok. Then I delete the migration and add a new class:
using System;
using System.Collections.Generic;
public class Blog
{
public int ID { get; set; }
public string Title { get; set; }
}
I add a reference to the context class:
public class LogoContext : DbContext
{
public DbSet<Word> Words { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Blog> Blogs { get; set; }
}
Then run Add-Migration InitialMigration again and get:
public partial class InitialMigration : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Blogs",
c => new
{
ID = c.Int(nullable: false, identity: true),
Content = c.String(maxLength: 4000),
})
.PrimaryKey(t => t.ID);
}
public override void Down()
{
DropTable("dbo.Blogs");
}
}
After running Update-Database I see:
Applying code-based migrations: [201304211225255_InitialMigration].
Applying code-based migration: 201304211225255_InitialMigration.
Running Seed method.
Now the problem appears - in my Server Explorer I examine the database Logo.sdf and it does not include the table Blogs! I even try to run this code from my app:
var db = new LogoContext();
db.Posts.Add(new Blog { Title= "moo" });
db.SaveChanges();
to check if maybe my Server Explorer isn't showing the table.. but I get an exception:
The specified table does not exist. [ Blogs ]
So the migrations are obviously not being applied to my Logo.sdf file :(
If I remove the connection string from app.config, the connection to a local instance of SQL Server Express is assumed. And there it works flawlessly!! When I examine the database with SQL Server Management Studio, I see the new Blogs table and also a system table for metadata about migrations...
Another little piece of information:
When I try to run Update-Database again, I get "No pending code-based migrations." and that tells me that some data is being saved to Logo.sdf after all... at least some metadata about migrations, but still I can't see that table in Server Explorer.
I'm using VS 2012 and EF 5.0.
Please help me understand this... It looks to me that something is seriously wrong because it just works with SQL Server Express instance, but not with SQL Server CE 4.0. :((
Thank you!
david

So the problem was that the solution created a separate .sdf file here:
"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Logo.sdf"
Which was unexpected and strange IMHO...
I ended up using this connection string:
<add name="LogoContext" connectionString="Data Source=|DataDirectory|\Logo.sdf" providerName="System.Data.SqlServerCE.4.0"/>
This references bin/Debug/Logo.sdf and it works during development and when running a .exe separately.
The only thing with this way is that my Logo.sdf project file (which was getting copied to Debug "if newer") is now completely ignored. All the migrations will be run on the Debug file.. That's probably good too....
Thanx Erik for the hint!
david

Related

Why is the wrong DB being updated by EF6?

I'm trying to use EF6 in my project and I've got two databases I'm trying to interact with. My app.config has connection strings for both, and I have two DbContext classes that pass in the app.config's key for the corresponding connection string. One context:
public LogProcessorContext() : base("LogProcessorDb")
{
}
public DbSet<LogFile> LogFiles { get; set; }
the other context:
public MessageTrackingContext() : base("MessageTrackingDb")
{
}
public DbSet<JournalLog> JournalLogs { get; set; }
but when I add the migration using add-migration NewBranch and update the db, a log file table gets added to the message tracking db (the wrong one), and the journallogs table doesn't get added at all. If anyone has any experience getting ef to play nice with multiple db/contexts, i'm all ears. I'm sure its just some simple mistake I'm making.
btw,
"LogProcessorDb"
and
"MessageTrackingDb"
are the keys in my app.config for my connection strings.
Thanks!

Models.ApplicationDbContext for all models in an Asp.Net MVC 5 application?

I've creating an Asp.Net MVC 5 website. I will need to add customized fields in ApplicationUser and associate (add foreign keys) it with other models. I think I should just use one context type. However, the code scaffold already generate the following ApplicationDbContext class. Can I just put all my public DbSet<...> ... { get; set; } in the class? Or is there a better pattern?
namespace MyApp.Models
{
// You can add profile data for the user by adding more properties to your User class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : User
{
}
public class ApplicationDbContext : IdentityDbContextWithCustomUser<ApplicationUser>
{
}
}
There is an excellent video explaining that matter.
Just check the free ASP.NET MVC 5 Fundamentals course by Scott Allen.
The exact answer is here (starts at 3:30).
I would advise keeping them separate. There is really no reason to couple two parts of the system together. To add another DbContext just add a file to models called YourContext.cs.
public class YourContext: DbContext
{
public YourContext() : base("name=YourContext")
{
}
// Add a DbSet for each one of your Entities
public DbSet<Room> Rooms { get; set; }
public DbSet<Meal> Meals { get; set; }
}
Then in the root web.config
<add name="YourContext" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=YourContext; Integrated Security=True"" providerName="System.Data.SqlClient" />
When you run enable-migrations in the package manager console you will be asked which dbcontext you want to migrate. Pick YourContext.
EDIT: No need to add repos / unit of work the Entity Framework does this for you.
Please note: This was written as in beta2 where ALLOT has changed! Hopefully most of it will stick but there are no guarantees until RC.
DO NOT USE NuGET package manger (until RC) as it does NOT pick-up on the .NET 5 packages required and it will install EF 6 and mess up your project. (We are after EF 7)
In the projects.json you need to have the following dependencies. (or beta2 when its out, or the latest on RC)
"EntityFramework": "7.0.0-beta1",
"EntityFramework.Relational": "7.0.0-beta1",
"EntityFramework.Commands": "7.0.0-beta1",
"EntityFramework.Migrations": "7.0.0-beta1",
"EntityFramework.SqlServer": "7.0.0-beta1"
Add a new folder DBContexts and add a c sharp file with your new context stuff.
public class BlaBlaDB : DbContext
{
public DbSet<Models.MyOtherModel> MyOtherModels { get; set; }
protected override void OnConfiguring(DbContextOptions options)
{
options.UseSqlServer();
}
}
and in your config.json make sure to add a connection string, the exact same as the IdentityDB just with you new name. Then in startup.json register your databse.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<DataContexts.IdentityDB>()
.AddDbContext<DataContexts.BlaBlaDB>();
This has to compile because k will run this project and use the startup to inject your context and then execute everything you need. As of now VS2015 Beta does NOT have all/ or they do not work, the command for EF.
You need to go and install KRE for Windows.
Open command prompt, browse to your project directory, enter the solution and enter the following commands.
k ef context list
k ef migration add -c (context.from.above) initial
k ef migration apply -c (context.from.above)
You now have multi context migration. Just keep on adding context and repeat this as you need it. I used this on localdb, as the default project set-up so that it can work stand alone in any environment, like Linux.
Please Note: You still need to create a Service, containing the Interface and Implementation and then register that in startup.json More information here

Changing the default SQL Server schema used from [dbo] to something else

I am using EF5 with the DefaultMembershipProvider and want to control the schema used in SQL Server for the tables created by the DefaultMembershipProvider.
EF5 says this is doable as:
modelBuidler.Entity<MyEntity>().ToTable("MyTable", "MySchema");
but as these are not "my" entities I cannot do it this way.
Questions:
1) So how do I do this in EF5?
2) Is this dealt with in EF6 when using DbModelBuilder.HasDefaultSchema?
Yes indeed I would upgrade to EF6 and then make your context look like this, e.g.:
public partial class BlogContext : DbContext
{
public BlogContext()
: base("BlogDb")
{
Database.SetInitializer<BlogContext>(null);
}
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingEntitySetNameConvention>();
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.HasDefaultSchema("");
}
}
You see setting the default schema at the end to "", which also works, in my case, Oracle 12c takes the login user name as schema and everything works fine. Of course you could also load the schema name from configuration and insert it there.
Note: Automatic migrations will NOT work anymore, as this seems to confuse the system quite much. See here for a possible solution so that at least explicit migrations will work somehow: Entity Framework using IdentityDbContext with Code First Automatic Migrations table location and schema?

Can't make EF Code First work with manually changed data base

I've added two new properties to my domain model class and two properties to a data table accordingly. Then I tried to launch my mvc web application and got
The model backing the 'EFDbContext' context has changed since the database was created.
Consider using Code First Migrations to update the database
(http://go.microsoft.com/fwlink/?LinkId=238269).
Having read the following posts:
MVC3 and Code First Migrations
EF 4.3 Automatic Migrations Walkthrough
I tried to Update-Database through Package Manager Console, but got an error
Get-Package : Не удается найти параметр, соответствующий имени параметра "ProjectName".
C:\Work\MVC\packages\EntityFramework.5.0.0\tools\EntityFramework.psm1:611 знак:40
+ $package = Get-Package -ProjectName <<<< $project.FullName | ?{ $_.Id -eq 'EntityFramework' }
+ CategoryInfo : InvalidArgument: (:) [Get-Package], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,NuGet.PowerShell.Commands.GetPackageCommand
The EntityFramework package is not installed on project 'Domain'.
But the Entityframework is installed on project Domain. I removed it from references, deleted package.config and sucessfully reinstalled EF. But Update-Database still returns same error. Update-Database -Config does as well
What am I doing wrong?
EDIT
Many thanks to Ladislav Mrnka, I'll try to rephrase my question. As far as I changed my data table manually, I am not expected to use migration. But how can I now make EF work with manually edited domain model class and data table?
Try to add this to startup of your application (you can put it to App_Start):
Database.SetInitializer<EFDbContext>(null);
It should turn off all logic related to handling the database from EF. You will now be fully responsible for keeping your database in sync with your model.
I had the same problem and this is how I fixed the issue.
I dropped table __MigrationHistory using sql command and run the update-database -verbose again.
Apparently something was wrong with this automatic created table.
Answer 2 was exactly what was needed. Although when I got to the App_Start I realized that there were 4 configuration files and didn't see where this would fit in any of them. Instead I added it to my EF database context
namespace JobTrack.Concrete
{
public class EFDbContext : DbContext
{
//Set the entity framework database context to the connection name
//in the Webconfig file for our SQL Server data source QSJTDB1
public EFDbContext() : base("name=EFDbConnection")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Remove the tight dependency on the entity framework that
//wants to take control of the database. EF by nature wants
//to drive the database so that the database changes conform
//to the model changes in the application. This will remove the
//control from the EF and leave the changes to the database admin
//side so that it continues to be in sync with the model.
Database.SetInitializer<EFDbContext>(null);
//Remove the default pluaralization of model names
//This will allow us to work with database table names that are singular
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
//Allows for multiple entries of the class State to be used with
//interface objects such as IQueryTables for the State database table
public DbSet<State> State { get; set; }
}
}

Entity Framework Code First Error "Error Locating Server/Instance Specified"

I'm trying to use Code First with my local instance of Sql Server 2008 R2. I've create a user 'dev' and can log in and create databases using Sql Managment Studio. The problem is I keep getting an error message when trying to create a database using DbContext in EntityFramework. Here is the error message:
"A network-related or instance-specific error occurred while
establishing a connection to SQL Server. The server was not found or
was not accessible. Verify that the instance name is correct and that
SQL Server is configured to allow remote connections. SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified"
The error message I checked my Sql Server and it does allow remote connections.
I've abstracted my system with the following code and get the same error:
namespace CodeFirstConsole
{
public class Program
{
static void Main(string[] args)
{
var db = new MyContext();
try { Console.WriteLine(db.Parents.Count()); }
catch (Exception) { throw; }
Console.Read();
}
}
internal class MyContext : DbContext
{
public DbSet<ParentObject> Parents { get; set; }
public DbSet<ChildObject> Children { get; set; }
public MyContext()
{
this.Database.Connection.ConnectionString =
"Data Source=.;Database=ConsoleTest;Initial Catalog=ConsoleTest;User ID=dev;Password=dev;";
}
}
internal class ParentObject
{
public int Id { get; set; }
public string PropertyOne { get; set; }
}
internal class ChildObject
{
public int Id { get; set; }
public bool PropertyOne { get; set; }
public string PropertyTwo { get; set; }
public virtual ParentObject Parent { get; set; }
}
internal class MyInitializer : DropCreateDatabaseAlways<MyContext>
{
protected override void Seed(MyContext context)
{
context.Parents.Add(new ParentObject() { PropertyOne = "hi" });
base.Seed(context);
}
}
}
I had the same error that drove me nuts for about a day. My situation was I had a large solution with a pre-existing start-up project and I was adding EF to the persistence project.
So the first step was to add the EF dependency. This created an app.config in my persistence project with the correct EF content. Then I went to Enable-Migrations and got the same error in this post. At this point I didn't think of copying the EF app.config settings to the app.config of the start-up project since I thought I'd have to play around with it before I would eventually run the app.
The problem was resolved when I changed the solution start-up project to the persistence project so I could get EF to find the correct app.config. Or I could have copied the EntityFramwework related section to the app.config of the start-up project.
Had the same error message developing on local, but it worked fine yesterday.
Turns out the wrong project in the solution was set as the StartUp Project.
So if you are also getting this message after an update-database command in the Package Manager Console, be sure to check if the correct StartUp Project is set.
For example the Web project, and not one of the helper projects.
Visual studio seems to have the habit of setting other projects as the StartUp by itself sometimes...
Try having a look here it explains a lot of the causes, since you indicated in the comments that you did explicitly specify server name and the code runs also on the same machine as sql server since from what I see the datasource just has a dot, indicating that its the same machine as the c# code program running on.
http://blogs.msdn.com/b/sql_protocols/archive/2007/05/13/sql-network-interfaces-error-26-error-locating-server-instance-specified.aspx
Had to add the EntityFramework dependency also to the startup project.
Install-Package EntityFramework
And also had to define connectionStrings to my main project App.config/Web.config.
<connectionStrings>
<add name="Database" providerName="System.Data.SqlClient" connectionString="foo.bar" />
</connectionStrings>
Here was a solution for me
Traditional SqlClient can find server instance but EF can't
In short:
Database.SetInitializer<MyContext>(
new MigrateDatabaseToLatestVersion<MyContext, Migrations.Configuration>(
useSuppliedContext: true));
Main part here is useSuppliedContext: true
I had the same problem and spent a whole day on it. Finally found #Christian's answer and now I find a much better way!
Put ConnectionString in the startup project. So you don't need to switch every time you change an entity.

Categories