EF Core 2 cross database migrations - entity-framework

I am trying to create a cross database migration by using EF Core 2.0
When I am at the office I work by using a shared sql server database with the team. For this reason the code uses a configuration that reference the sql server provider
optionsBuilder.UseSqlServer(connectionString, serverOptions => {
serverOptions.MigrationsHistoryTable("__EFMigrations", "dbo");
});
When a new migration is created this make the migration code use specific configuration of the sql server provider like
migrationBuilder.CreateTable(
name: "Customers",
schema: "dbo",
columns: table => new
{
EntityID = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(maxLength: 255, nullable: false)
},
constraints: table => {
table.PrimaryKey("PK_Customers", x => x.EntityID);
});
Please note the Annotation method.
When out of office I am using a postgreSQL instance installed on my mac and I need to have a slightly different migration which makes use of the specific postgreSQL provider
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
I know that I can manually modify the migration to specify both annotation as this does not have impact when running on a specifica database type.
However manually modify the migration is a tedious and error prone job that I would like to avoid.
Is there any way to make EF generate both Annotation methods automatically?
I have also tried to use the DbContext OnModelCreating method by specifying options on the ModelBuilder
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
or
modelBuilder.ForNpgsqlUseSerialColumns();
modelBuilder.ForSqlServerUseIdentityColumns();
but the generated migration it is always related to the provider used at that specific moment.

There is no way to get EF Core to do it for you. What you're doing is the best approach. A slightly less tedious approach is to keep two separate sets of migrations--one for each provider.
See EF Core Migrations with Multiple Providers for more details.

Related

Entity Framework Core - Use generated query

I have a structure of 26 tables which I want to load data from the database and get them inside the code. For example I use the Include method to join the related data of an entity:
var Application = dbContext.Applications
.Include(a => a.PwEmployee)
.Include(a => a.Promoters).ThenInclude(f => f.Addresses)
.Include(a => a.Promoters).ThenInclude(f => f.People)
... and many more
I don't want to include the generated query since it is not that readable and also not the problem here. What I want to do is use the generated query in a stored procedure and do this:
List<Application> Applications = await dbContext.Applications.FromSqlRaw("Exec GetFullApplication {0}", uuid).ToListAsync();
When I do this with the generated SQL query from EF Core, I get an exception:
System.ArgumentException: An item with the same key has already been added. Key: ID
When it works from EF Core to the database, shouldn't it work also the other way around with said SQL statement that EF Core generated? Is there any performance improvement to expect when doing this?

How to select data from old database and insert it into new one within doctrine migration?

I use 'doctrine/DoctrineORMModule' module for zend framework 3 (MVC). I have configured 'orm_default' and can configure 'orm_old' but don't know how to use 'orm_old' within migration file.
I can do this within migration file:
public function up(Schema $schema) : void
{
$sql = "INSERT INTO `some_table` VALUES ('some_value','','',NULL,NULL,'1');";
$this->addSql($sql);
//...
But in general I need run something like this:
INSERT INTO DB2.T2(id, title, description)
SELECT id, title, description FROM DB1.T1;
How to do that?
If I understand correctly, you'd like to use Doctrine Migrations for two database connections: orm_default and orm_old.
This is possible in Doctrine, but not with the Zend Framework DoctrineORMModule. This is mentioned very shortly in the official documentation: https://github.com/doctrine/DoctrineORMModule/blob/master/docs/migrations.rst#multiple-migration-configurations
The best thing you can do is to use two separate cli-config files with the same database connections, and put the migrations in two seperate folders. You can then use the 'default' doctrine CLI tools (vendor/bin/doctrine migrations:migrate ) to run migrations for the two connections.
Adding this functionality to the DoctrineORMModule was requested, but never implemented. You can read more about it right here:
https://github.com/doctrine/DoctrineORMModule/issues/537

Entity Framework Core Data Type Conversion differences between SQLite vs SQLServer

I have a SQLite and SQL Express databases both of which have a table with the columns as below:
my simplified Entity look as below:
public class Customer
{
public string BusinessIdentifier { get; set; }
}
if you notice the datatype is different between the Database bigint vs string on my entity for an example.
I have used a Fluent API to do the mapping as shown below:
entity.Property(p => p.BusinessIdentifier).HasColumnName("CUSTOMER")
on the SQLite when i use options.UseSqlite(connectionString); this work just fine. For SQLite connectionString="Data Source=my_db.db"
however when I use SQL Server Express using options.UseSqlServer(connectionString); it starts to give me errors on the type mismatch.
I have to explicitly handle this conversion on the Fluent API as below:
entity.Property(p => p.BusinessIdentifier).HasColumnName("CUSTOMER").HasConversion(v => Convert.ToInt64(v), v => v.ToString());
SQL Server connectionString="Data Source=my_machine\SQLEXPRESS;Initial Catalog=my_db;Integrated Security=True;"
Question:
Can someone please explain why is this difference between the 2 types of databases and is it really needed to be so specific in every case?
Regards
Kiran
SQLite does not force for data type constraints, It allows you the store a value which is of different data type, so this might be the reason that your code works fine with SQLite, On the other hand, SQL Server enforces you to have to the same datatype.
You can refer to this doc https://www.sqlite.org/datatype3.html.

Dis-Advantages of using EF 6.x.x Code First without Migration

I am fed up of using/running Add-Migration and Update-Database because lot of time we forget to run migrations on production database. So, we decided to delete all migrations from database table as well all migration classes. So, what if my __MigrationHistory table remains always empty and no migration classes. What is the main disadvantage?
No this is a bad idea, the [__MigrationHistory] is used to compare your current used conceptual model with the storage model.
1) Case: DbMigrationsConfiguration automatic:
[__MigrationHistory] keeps track for the last migration.
this.AutomaticMigrationsEnabled = true;
this.AutomaticMigrationDataLossAllowed = true;
as shown in the image above, the migrationId is the migration identifier and the model column is a base64 representation of the binary stream of your current conceptual model.
2) Case: DbMigrationsConfiguration non-automatic:
[__MigrationHistory] keeps track of every migration.
this.AutomaticMigrationsEnabled = false;
this.AutomaticMigrationDataLossAllowed = false;
Each migration level obtain a migrationId identifier which is used for migration level up/level/down.
Best practice: If you want to use the automatic migration just regenerate the migration and shipped to the custmer.
If you are using non-automatic migration.
1) If the customer need the data then just tranform the data with SQL to the new db schema
2) If the customer does not need the data then just drop the database an create it again with initialCreate.
If you want to create the database without any migrationHistory info:
// Create the database. You can generate it from SMO "Script database as" and if the database exist then just ignore the creation
// Do not forget to remove the [__MigrationHistory] rows.
DbContext.Database.ExecuteSqlCommand("SQLCreateDbScript.sql");
Database.SetInitializer<MyDbContext>(null);
using (var dbContext = new MyDbContext())
{
// Create DbContext and it works!
dbContext.Users.Add(new User());
dbContext.SaveChanges();
}
I hope this will help you to solve the problem!
And if you want something really with less Db-Schema then use NoSql with EF.
In Core version still not done but with the old version EF6 it is possible todo that (NoSql Db) with: http://www.brightstardb.com or use the Polyglot appoarch from microsoft https://msdn.microsoft.com/en-us/library/dn271399.aspx

How to affect the column order with Entity Framework Code First Migrations

I'm using Entity Framework 4.3 Code First and trying out the Migrations feature.
If I add a new property to my class and then run Add-Migration from the package manager console window I get something like this:
public override void Up()
{
AddColumn("Products", "Discontinued", c => c.Boolean(nullable: false));
}
I would like to be able to affect the order of the column as I don't want it to just be appended to the table but rather placed at a specific index. I thought I might be able to add it to my modelBuilder configuration, something like:
Property(p => p.Discontinued).HasColumnOrder(2);
but running Update-database does not appear to use it. Can this be done as a migration?
This is just a matter of missing functionality. SQL by itself does not rely on any implicit order of columns (with some exceptions: ORDER BY , ...).
Neither SQL Server nor ORACLE do have a direct SQL DDL command (aka ALTER TABLE...) to move a column around.
Therefore there's no possibility to change the order without high effort (recreate the table). See for example
How To change the column order of An Existing Table in SQL Server 2008
SQL SERVER – Change Order of Column In Database Tables
https://dba.stackexchange.com/questions/61978/how-to-change-the-column-order