I'm using EF6 Code First Migrations for Multiple Models means working with a single database via multiple dbContext and Migrations, In MVC5!
Why?
Because i want to add new Entities to database from my Areas!..So each Area have their own dbContext and Migrations Files. i use Update-Database command in console package manager and my database will update without any problem.
As every body knows: You can update your database from each projects of your solution but if you set it as StartUpProject of solution.
and my challenge is about what i said in above Blockquote ! because in another step i want to update my database programmatically by this code:
//ActionResult of my Area:
public ActionResult Create()
{
var configuration = new Configuration();
var migrator = new DbMigrator(configuration);
migrator.Update(); //got Error in this line
return View();
}
i get
network-related or instance-specific error
in specified line and i know why!..because my Area Project is not set as StartUpProject of my solution and it shouldn't be.
So how can i handle this situation in your view?
I knew. i should give ConnectionString to my configuration instance, straightly like this:
public ActionResult Create()
{
var configuration = new Configuration();
configuration.TargetDatabase = new DbConnectionInfo(
"Server=.;Database=SegalFrameWork;Trusted_Connection=True;",
"System.Data.SqlClient");
configuration.ContextKey = "BlogDbContext";
var migrator = new DbMigrator(configuration);
migrator.Update();
return View();
}
now there is no need to read connection string from web.config so it doesn't need any startup project to find it.
Related
I've not used VS MVC for a while but I'm writing a project which requires connecting to a Sql database which I've installed as an edmx file SwitchDB.edmx in my DAL folder. In the past I've set up my data context file which I then use to reference the data in my controller, the model help me to order the data in the correct way.
This is how my data context file looks
namespace Switches.DAL
{
public class SwitchContext : DbContext
{
public SwitchContext()
: base("DefaultConnection")
{ }
public DbSet<Switch_List> SwitchList { get; set; }
}
}
I've set up the "DefaultConnection" in my Web.config under connectionStrings and my model Switch_List.cs has the file settings. When I declare the DB context in my controller as below
private SwitchContext db = new SwitchContext();
Then I would expect to reference the SwitchContext to get my data, like this
var switches= db.SwitchList .ToList();
However, when I run the project and reference db in debug I get the following error message 'the function evaluation requires all threads to run'. The DB context SwitchContext is clearly not getting access to the Switch.edmx so what am I forgetting?
I had a similar problem, but you should see the connection properties using an IDE button (to re-evaluate the expression).
However, when you get to the part of db.SwitchList.ToList() does it generate any exceptions?
I'm getting the following error in my web API application.
"An entity object cannot be referenced by multiple instances of IEntityChangeTracker"
Step 1: Browser posts an edited Release to API controller, which in turn calls update on a Service.
ReleaseController.cs
public Guid Update(EditReleaseViewModel release)
{
if (!ModelState.IsValid) throw new Exception("Invalid model");
var updatedRelease = _releaseService.Update(release);
return updatedRelease.ID;
}
Step 2: Service retrieves and modifies the Release. (The service gets the DbContext injected per request with Ninject)
ReleaseService.cs
public Release Update(EditReleaseViewModel release)
{
var existingRelease = _context.Releases.Single(x => x.ID == release.ID);
existingRelease.Name = release.Name;
existingRelease.CatalogNumber = release.CatalogNumber;
_context.Entry(existingRelease).State = EntityState.Modified; // ERROR HAPPENS HERE!
_context.SaveChanges();
return existingRelease;
}
I read that this happens when an entity is still in memory (wasn't detached before disposing previous DbContext).
Could the problem be that I'm using the same Service to retrieve the Release before trying to update it again in that same service?
And if yes, what's the best way around this? Thanks!
When you retrieve existingRelease from the dbcontext one of the benefits is your context is already attached and your state tracking is provided for free. All you need to do is update your name/catalognumber and call SaveChanges.
public Release Update(EditReleaseViewModel release)
{
var existingRelease = _context.Releases.Single(x => x.ID == release.ID);
existingRelease.Name = release.Name;
existingRelease.CatalogNumber = release.CatalogNumber;
_context.SaveChanges();
return existingRelease;
}
When you manually set the state of the entity like so:
_context.Entry(existingRelease).State = EntityState.Modified;
Two things happen here: 1) it tries to attach existingRelease to _context (which fails here because it's already attached to it from the retrieval) and 2) marks ALL properties as modified -- rather than only the 2 you've updated.
Hope that helps.
The situation is :
Per tenant db.
Non-automatic Code-based based migration. The initial creation of the dbs is through Code First too. There are no preexisting dbs in the current scenario.
The exact db is not known during the generation of migration script becase there are many. The only thing I have is code - the Initial migration script based on the model in the beginning and the model with some modifications.
Existing dbs generated with initial script - everything works fine. Here is how I reproduce the problem :
Run PS command : Add-Migration -Name Initial -StartUpProjectName MyApp.Web -ProjectName MyApp.Migrations -ConfigurationTypeName "MyApp.Migrations.MyMigrationConfiguration" -ConnectionString "Data Source=.\SQLEXPRESS;Database=demo-db;Trusted_Connection=False;User ID=x;Password=x" -ConnectionProviderName "System.Data.SqlClient" - Works Fine
Run the app and the db is created. Stop the app. Make modification to the model.
Run PS command : Add-Migration -Name MySecondMigration -StartUpProjectName MyApp.Web -ProjectName MyApp.Migrations -ConfigurationTypeName "MyApp.Migrations.MyMigrationConfiguration" -ConnectionString "Data Source=.\SQLEXPRESS;Database=demo-db;Trusted_Connection=False;User ID=x;Password=x" -ConnectionProviderName "System.Data.SqlClient" - Boom.
Subtlety - The migrator does not even connect to MSSQL to check if the db even exists or has dbo.__MigrationHistory! I have goen further and turned off the MSSQL service! - It does not matter if I enter false db name or not or I turn off the entire MSSQL server - the error is the same and no connection is made. So how does it know a migration is pending when it does not check the database? I assume a bug.
I have __dbo.MigrationHistory created already with the Initial migration in it.
Error : Unable to generate an explicit migration because the following explicit migrations are pending: [201402121953301_Initial]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
Here is my Configuration - nothing special :
public class MyMigrationConfiguration : DbMigrationsConfiguration<MyMigrationContext>
{
public MyMigrationConfiguration()
{
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
MigrationsNamespace = "---";
MigrationsDirectory = "---";
}
}
Here is the method with wich I create the dbs :
public void CreateOrUpdateDb(string DbName)
{
try
{
string connectionString = _connectionStringProvider.GetConnectionString(DbName);
DbMigrationsConfiguration cfg = CreateMigrationsConfig(connectionString);
cfg.AutomaticMigrationsEnabled = false;
cfg.AutomaticMigrationDataLossAllowed = false;
DbMigrator dbMigrator = new DbMigrator(cfg);
dbMigrator.Update();
}
catch (MigrationsException exception)
{
_logger.Error(string.Format("Error creating database '{0}'",DbName), exception);
}
}
I have already searched and read whatever I can find on the web but most examples include the standart Configuration.cs and the like. Nobody explains why should I run Enable-Migrations because it creates Configuration.cs but I provide the Configuration class myself and do not need this other class.
Here is the exception stack :
> System.Data.Entity.Migrations.Infrastructure.MigrationsPendingException: Unable to generate an explicit migration because the following explicit migrations are pending: [201402121953301_Initial]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
at System.Data.Entity.Migrations.DbMigrator.Scaffold(String migrationName, String namespace, Boolean ignoreChanges)
at System.Data.Entity.Migrations.Design.MigrationScaffolder.Scaffold(String migrationName, Boolean ignoreChanges)
at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Scaffold(MigrationScaffolder scaffolder)
at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Scaffold(String migrationName, String language, String rootNamespace, Boolean ignoreChanges)
at System.Data.Entity.Migrations.AddMigrationCommand.Execute(String name, Boolean force, Boolean ignoreChanges)
at System.Data.Entity.Migrations.AddMigrationCommand.<>c__DisplayClass2.<.ctor>b__0()
Is there any way to force the migrator to make the script without telling me that there are some pending migrations even though there are not? This is 100% bug in EF but I do not know how to get around it.
We have found the answer - a smart colleague of mine and with the help of Reflector.
Inside EntityFramework.dll there is the class
System.Data.Entity.Migrations.DbMigrator with a method
Scaffold(string migrationName, string #namespace, bool ignoreChanges)
Which makes a call this.GetPendingMigrations
Which method calls another method on another class HistoryRepository.CreateHistoryQuery(HistoryContext context, string contextKey = null) with the parameter contextKey == NULL
But there inside this method this happens
contextKey = !string.IsNullOrWhiteSpace(contextKey) ? contextKey.RestrictTo(this._contextKeyMaxLength) : this._contextKey;
and the contextKey is not null anymore. IT actually becomes the type(YourInheritedDbMigrationConfiguration).ToString()
Where is the problem? The problem lies in the fact that
I use two different DbMigrationConfiguration classes
because the migration assembly is separated from the core of the application which makes
them two differently 'fully qualified named classes' which at the end
result in two different ContextKeys in the dbo._MigrationHistory table for the DbMigrationConfiguration which is used for the generation of the migration script.
So when I make the initial migration script and start the site and the site applies the script it is ok but in the dbo._MigrationHistory the ContextKey is "MyDbConigClass1". After that when I try Add-Migration which uses another DbMigrationConfiguration class the ContextKeys does not match - BOOM!
The solution : Added the same ContextKey = "MyTenantDb" in both of my configuration classes and everything started to work again because the type names no longer got involved but the DbMigrator used my custom ContextKey :)
I am using EF Code First Migration with ASP.NET MVC5 project. I want to seed the database with about 5000 records. The examples on the asp.net web site and blogs all have the seed function within the configuration method.
internal sealed class Configuration : DbMigrationsConfiguration<foo.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\ApplicationDbContext";
}
protected override void Seed(foo.ApplicationDbContext context)
{
SeedProducts(context);
SeedFoods(context);
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
What are some options to seed large data sets when using EF Migration?
Currently The configuration file is over 5000 lines long and is different to manage.
I would prefer to store them in another database or excel spreadsheet and then import them in using the seed function. I am not sure how to go about importing data from external sources within the Seed method.
I also tried to break up the data set into several files but when I try to call the function
SeedProducts(context);
SeedFoods(context);
outside of the Configuration Class I get a build error: "The name does not exists in the current context". (I am not sure what this means?
You can store the sql file in the base directory and use it. You can create multiple sql files. I used following code to execute all sql files stored on base directory.
protected override void Seed(CRM.Data.DbContexts.CRMContext context)
{
var sqlfiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory+"\\initialdata", "*.sql");
sqlfiles.ToList().ForEach(x=> context.Database.ExecuteSqlCommand(File.ReadAllText(x)));
}
Why we need to have a seed data for 5000 records. If you prefer this way it will take lot of manual work also. where as, its not required here.
Instantly you can Create Scripts and execute that into you db. via Code as well as Manually.
Db Scripts can be taken for entire db as well as each table, Store Procedure wise also. So, that you will get records particularly.
Follow the steps from this link OR MSDN
Note: After Creating the Database Script. You can read the file from Seed Function and Execute the query from function itself. Or Manually you can go and execute when ever you need it.
I ended up using a CSV (comma delimited file) and storing it as a domain resource. Then reading the CSV file and adding database records:
I am able to Seed the database using EF Migration Seed method and a CSV file as defined as follows in the Migration.cs file. Note: the CSV file in the project in Visual Studio are set to the Build Action to Embedded Resource.
public void SeedData(WebApp.Models.ApplicationDbContext Context)
{
Assembly assembly = Assembly.GetExecutingAssembly();
string resourceName = "WebApp.SeedData.Name.csv";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
CsvReader csvReader = new CsvReader(reader);
csvReader.Configuration.WillThrowOnMissingField = false;
var records = csvReader.GetRecords<Products>().ToArray();
foreach (Product record in records)
{
Context.Products.AddOrUpdate(record);
}
}
}
Context.SaveChanges();
}
Psssst...!
Read on, by all means. But I can tell you here that the problem had nothing to do with the DataContext, but with Dependency Injection. I have left the question up, as it documents one possible issue with the "row not found or changed error" that has nothing to do with real world concurrency conflicts.
It seems the problems have been caused by badly written dependency injection. Or rather, I am beginning to believe, by default lifecycle management by the DI container I used.
The problem was that I used a DataContext as a constructor argument that was supplied by Ninject. It seems that the default behaviour was to cache this DataContext, leading to all manner of unexpected behaviour. I will ask a separate question about this.
Anyway, what follows is my original question, which as you will see, misses the real cause of the issue by a mile...
The Problem
I am getting a number of errors that imply that the DataContext, or rather, the way I am using the DataContext is getting out of synch.
The error occurs on db.SubmitChanges() where db is my DataContext instance. The error is:
Row not found or changed.
The problem only occurs intermitently, for example, adding a row then deleting it. If I stop the dev server and restart, the added row is there and I can delete it no problem.
Ie, it seems that the problem is related to the DataContext losing track of the rows that have been added.
IMPORTANT:
Before anyone votes to close this thread, on the basis of it being a duplicate, I have checked the sql server profiler and there is no "Where 0 = 1" in the SQL.
I have also recreated the dbml file, so am satisfied that the database schema is in synch with the schema represented by the dbml file.
Ie, no cases of mismatched nullable/not nullable columns, etc.
My Diagnosis (for what it is worth):
The problem seems (to me) related to how I am using the DataContext. I am new to MVC, Repositories and Services patterns, so suspect that I have wired things up wrong.
The Setup
Simple eLearning app in its early stages. Pupils need to be able to add and delete courses (Courses table) to their UserCourses.
To do this, I have a service that gets a specific DataContext instance Dependency Injected into its constructor.
Service Class Constructor:
public class SqlPupilBlockService : IPupilBlockService
{
DataContext db;
public SqlPupilBlockService(DataContext db)
{
this.db = db;
CoursesRepository = new SqlRepository<Course>(db);
UserCoursesRepository = new SqlRepository<UserCourse>(db);
}
// Etc, etc
}
The CoursesRepository and UserCoursesRepository are both private properties of the service class that are of type IRepository (just a simple generic repository interface).
SqlRepository Code:
public class SqlRepository<T> : IRepository<T> where T : class
{
DataContext db;
public SqlRepository(DataContext db)
{
this.db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
db.SubmitChanges();
}
#endregion
}
The two methods for adding and deleting UserCourses are:
Service Methods for Adding and Deleting UserCourses:
public void AddUserCourse(int courseId)
{
UserCourse uc = new UserCourse();
uc.IdCourse = courseId;
uc.IdUser = UserId;
uc.DateCreated = DateTime.Now;
uc.DateAmended = DateTime.Now;
uc.Role = "Pupil";
uc.CourseNotes = string.Empty;
uc.ActiveStepIndex = 0;
UserCoursesRepository.Add(uc);
UserCoursesRepository.Save();
}
public void DeleteUserCourse(int courseId)
{
var uc = (UserCoursesRepository.Query.Where(x => x.IdUser == UserId && x.IdCourse == courseId)).Single();
UserCoursesRepository.Delete(uc);
UserCoursesRepository.Save();
}
Ajax
I am using Ajax via Ajax.BeginForm
I don't think that is relevant.
ASP.NET MVC 3
I am using mvc3, but don't think that is relevant: the errors are related to model code.
The problem only occurs intermitently,
for example, adding a row then
deleting it. If I stop the dev server
and restart, the added row is there
and I can delete it no problem.
Your code does not show what the link is between the Added Row and the Delete/Update. Your Add() doesn't return an object reference.
I'm thinking you are missing a Refresh (ie reload the object after Insert). Is your IdCourse also the PK in the Table?
Edit:
Further research has revealed that the problem is with the dependency injection.
The problem was related to how Dependency Injection manages the items it creates. Google for 'lifecycle management' in IoC or DI. Essentially, DI cached a DataContext constructor argument that I injected.
For a way to solve this using the Factory Pattern, see this thread:
Ninject caching an injected DataContext? Lifecycle Management?
The accepted answer solved it all.