SchemaUpdate doesn't work - c#

I made changes to the mapping (added a new table, changed some existing ones), started my app and SchemaUpdate didn't do anything and also didn't throw an exception. I checked with pgAdmin and the schema wasn't updated.
if (sessionFactory == null) {
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(Building).Assembly);
new SchemaUpdate(configuration).Execute(true, true);
sessionFactory = configuration.BuildSessionFactory();
}
How can I make SchemaUpdate work?
Edit: There are also no exceptions stored in the SchemaUpdate Exceptions property.
Edit2: Nhibernate Version v4.0.30319, not using Fluent.
I tried to export the generated SQL, but the Action is never called.

Apparently, SchemaUpdate only does nothing to a table if it exists. So, the only way to update a table using SchemaUpdate is to manually delete it before application startup.

Related

Microsoft.EntityFrameworkCore.SqlServer - Database not updating on context.Database.Migrate();

I'm trying to move a project from using Dapper to Microsoft.EntityFrameworkCore.SqlServer.
I've created the entities and their respective mappings(configurations).
Also I'm running in my ConfigureServices method inside startup.
using var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope();
using var context = scope.ServiceProvider.GetRequiredService<SpannerContext>();
context.Database.EnsureCreated();
context.Database.Migrate();
But nothing is happening;
Logs shows:
info: Microsoft.EntityFrameworkCore.Migrations[20405]
No migrations were applied. The database is already up to date.
But I've added some new DbSets and also change some column types
Am I missing something?
try to generate your models and configuration form an existing database, then apply the modifications/changes in your models.
https://www.entityframeworktutorial.net/efcore/create-model-for-existing-database-in-ef-core.aspx
I order to solve the problem i followed the following steps
Scaffold the database;
Add a migration;
Run the code for the first time, to ensure the entity framework migrations table is created;
Go to the entity framework table and add the name of the create migration;
Modify the database with the new tables/columns e etc;
Add a new migration;
The new migration should work as expected;
This way you don't need to comment the up part of the code;

DbMigrator does not detect pending migrations after switching database

EntityFramework migrations become useless after switching to new Context.
DbMigrator is using list of Pending Migrations from first database instance, which makes means no migrations are applied to other databases, which then leads to errors during Seed();
C# .NET 4.5 MVC project with EF 6
MS SQL Server 2014, multiple instances of same database model.
CodeFirst approach with migrations.
DbContext initializer is set to null.
On Application Start we have custom Db Initialization to create and update databases. CreateDatabaseIfNotExists is working as intended, new databases have all migrations applied. However both MigrateDatabaseToLatestVersion initializer and our custom one are failing to update databases other than first one on list.
foreach (var connectionString in connectionStrings)
{
using (var context = new ApplicationDbContext(connectionString))
{
//Create database
var created = context.Database.CreateIfNotExists();
var conf = new Workshop.Migrations.Configuration();
var migrator = new DbMigrator(conf);
migrator.Update();
//initial values
conf.RunSeed(context);
}
}
context.Database.CreateIfNotExists(); works correctly.
migrator.GetLocalMigrations() is always returning correct values.
migrator.GetPendingMigrations() after first database is returning
empty list.
migrator.GetDatabaseMigrations() is mirror of pending migrations,
after first database it contains full list event for empty databases.
Fetching data (context.xxx.ToList()) from Db instance confirms connection is up and working, and links to correct instance.
Forcing update to most recent migration with migrator.Update("migration_name"); changes nothing. From what I gather by reading EF source code, it checks pending migration list on its own, which gives it faulty results.
There seems to be some caching going in under the hood, but it eludes me how to reset it.
Is there a way to perform migrations on multiple databases or is it yet another "bug by design" in EF?
Edit:
Real problem is DbMigrator creating new Context for its own use. It does it via default parameterless constructor, which in my case had fallback to default (first) connection string in web.Config.
I do not see good solution for this problem but primitive workaround in my case is to temporarily edit default connection string:
var originalConStr = WebConfigurationManager.ConnectionStrings["ApplicationDbContext"].ConnectionString;
var setting = WebConfigurationManager.ConnectionStrings["ApplicationDbContext"];
var fi = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
//disable readonly flag on field
fi.SetValue(setting, false);
setting.ConnectionString = temporaryConnectionString; //now it works
//DO STUFF
setting.ConnectionString = originalConStr; //revert changes
Cheat from: How do I set a connection string config programatically in .net?
I still hope someone will find real solution so for now I will refrain with self-answer.
You need to correctly set DbMigrationsConfiguration.TargetDatabase property, otherwise the migrator will use the default connection info.
So in theory you can do something like this
conf.TargetDatabase = new System.Data.Entity.Infrastructure.DbConnectionInfo(...);
Unfortunately the only 2 public constructors of the DbConnectionInfo are
public DbConnectionInfo(string connectionName)
connectionName: The name of the connection string in the application configuration.
and
public DbConnectionInfo(string connectionString, string providerInvariantName)
connectionString: The connection string to use for the connection.
providerInvariantName: The name of the provider to use for the connection. Use 'System.Data.SqlClient' for SQL Server.
I see you have the connection string, but have no idea how you can get the providerInvariantName.
UPDATE: I didn't find a good "official" way of taking the needed information, so I've ended using a hack with accessing internal members via reflection, but still IMO it's a quite more safer than what you have used:
var internalContext = context.GetType().GetProperty("InternalContext", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(context);
var providerName = (string)internalContext.GetType().GetProperty("ProviderName").GetValue(internalContext);
var conf = new Workshop.Migrations.Configuration();
conf.TargetDatabase = new System.Data.Entity.Infrastructure.DbConnectionInfo(connectionString, providerName);

Ado.net firebird commit insert new lines to table

I'm adding new lines to a database for our company's "order list" for each order created, using the firebird ado.net client. The code i've written works fine for listing items, but inserting new ones doesn't appear elsewhere (e.g. in flamerobin). What I think is happening is that the transaction isn't being committed, seeing as it's recognised within my code (can't add duplicate values).
Code:
using (FbConnection fbCon = new FbConnection)
{
fbCon.Open();
***command w/ parameterised command string***
using (FbTransaction fbTrans = fbCon.BeginTransaction())
using FbCommand orderCommand = new FbCommand(cmdString, fbCon, fbTrans)
{
***Adding parameters and values***
try
{
int recordsAffected = orderCommand.ExecuteNonQuery();
fbTrans.Commit();
}
catch (FbException E)
{
fbTrans.Rollback();
fbCon.Close();
throw E
}
}
recordsAffected returns 1 but I am not able to see the updated values in flamerobin or the db management program. Am i missing something?
If anyone else runs into this problem, it's in Visual Studio's debugging settings. https://visualstudiomagazine.com/blogs/tool-tracker/2012/05/dealing-with-local-databases-or-why-your-updates-dont-stick.aspx explains pretty clearly, but basically VS makes a copy of your database in bin/Debug of your project (Ostensibly to not mess with your data) but if you actually need to use/view the data externally, either link your external application to the debug database (e.g. flamerobin). You may also need to set your project database settings to Copy if Newer if you want your updates to stay, as the default setting copies the database into the folder each time you run your c# app.

SqLite in memory database : CREATE TABLE does not work?

When using this code on a SqLite file database, it works fine.
using (var ctx = new Test2010Entities())
{
string s = "CREATE TABLE 'Company' ([Id] integer PRIMARY KEY AUTOINCREMENT NOT NULL, varchar(50) NOT NULL);";
ctx.ExecuteStoreCommand(s);
ctx.Companies.AddObject(new Company { Code = "_1" });
ctx.Companies.AddObject(new Company { Code = "_2" });
ctx.SaveChanges();
foreach (var c in ctx.Companies.ToList())
{
Console.WriteLine(c.Code);
}
}
But when runnning this code on a SqLite 'In Memory' database (Data Source=:memory:;Version=3;New=True;) , I get this exception:
Unhandled Exception: System.Data.UpdateException: An error occurred
while updating the entries. See the inner exception for details. --->
System.Data.SQLite.SQLiteException: SQL logic error or missing
database no such table: Company
Note this is tested with VS 2010, EF 4.4.0.0 and sqlite-netFx40-setup-bundle-x86-2010-1.0.84.0
::: UPDATE :::
As Simon Svensson suggested, opening the connection before any other commands does do the trick:
ctx.Connection.Open();
This happens when your ORM closes your connection, and reopens it. That will reset the sqlite in-memory database to its default state; i.e. empty.
The same thing happens with NHibernate unless you set connection.release_mode = close (the default is after_transaction.
I'm not familiar with Entity Framework, but I expect a similar setting or using the DataContext(IDbConnection) constructor which is documented as "If you provide an open connection, the DataContext will not close it."
The same documentation also states "In a System.Transactions transaction, a DataContext will not open or close a connection to avoid promotion." which may be a cleaner solution.
Using some Reflector magic shows that it's SQLiteConnection.Open that calls (via SQLite3.Open) sqlite3_open_interop (if you're using the NuGet sqlite package). This shows that you get a new empty in-memory database everytime you call SQLiteConnection.Open.

EntityFramework CodeFirst and EDMX together in TransactionScope

I need to combine in one application
code generated from DB to EDMX file before compilation and
code generated and compiled during runtime by application itself, where generated code uses CodeFirst to access DB.
Remark: Codes in 1. and 2. have different DbContexts, access same database, but different tables.
It looks, that when I am using instances of type 1. and 2. in different transaction scopes, everything works fine. But when I try to use them together in one transaction scope, I get error (in case when EDMX is called first)
System.Reflection.TargetInvocationException: Exception has been thrown by the ta
rget of an invocation. ---> System.Data.ProviderIncompatibleException: An error
occurred while getting provider information from the database. This can be cause
d by Entity Framework using an incorrect connection string. Check the inner exce
ptions for details and ensure that the connection string is correct. ---> System
.Data.ProviderIncompatibleException: **The provider did not return a ProviderManif
estToken string.** ---> System.Transactions.TransactionException: **The operation is
not valid for the state of the transaction.**
and error (in case when CodeFirst is used first)
System.Data.MetadataException: Schema specified is not valid. Errors:
(0,0) : error 0175: **The specified store provider cannot be found in the configur
ation, or is not valid.**
at System.Data.Metadata.Edm.StoreItemCollection.Loader.ThrowOnNonWarningErrors()
To complicate my situation even more I have to add this: described behaviour I have only in case when DB is on remote server. If I am working with local DB, everything looks OK. My suspicion is that Distributed Transaction Coordinator can play its role...
Main question: is it possible to combine EDMX and CodeFirst in one TransactionScope. If yes then how?
Any help would be appreciated. Milos
CodeFirst creates an EDMX based on your classes and it's not possible to load an exisiting edmx file. However you can generate classes from your database (e.g. using EF Power Tools) and configure your model so that the EDMX generated by your CodeFirst app is the same as the one you would like to load. You can use TransactionScope with Entity Framework. The error messages you are getting are not related to transaction scope but to a missing or incorrectly used provider.
I used code first to save to two different databases came up with errors connection string was wrong so i did this and it worked....
try
{
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
MegaBotExtractorDBContext2 db = new MegaBotExtractorDBContext2();
MegaBotExtractorDBContext db1 = new MegaBotExtractorDBContext();
FullUri newUri = new FullUri();
HostUri NewHostUri = new HostUri { HostUriName = "google10.com" };
db1.HostUris.Add(NewHostUri);
db1.SaveChanges();
using (TransactionScope ts2 = new TransactionScope(TransactionScopeOption.RequiresNew))
{
db.FullUris.Add(newUri);
db.SaveChanges();
ts2.Complete();
ts.Complete();
}
}
}
catch { }

Categories

Resources