Entity Framework Code First - T-SQL Views - c#

I'm creating a SQL View on my Configuration Seed
protected override void Seed(QuiverContext context)
{
context.Database.ExecuteSqlCommand(DatabaseScripts.Views.MyView);
}
Now I want to add a DBSet to my DbContext that represents my View. I read that one can do this using then the Entity like a regular table.
So I tried but it requires me to add a migration which I did, but then the update-database command fails when creating the view since a table is created first.

It looks like you're trying to create a view in your Seed method. This isn't the way to create a view (remember the seed method runs every time ANY migration runs).
The better way to be would be to add a migration. This will create a code file containing CreateTable lines, which will make your table. Just remove these lines, and replace them with a call to create your view.
You can execute custom Sql inside a migration using the Sql command, for example...
Sql("CREATE VIEW myView.....");
If you want to make things a bit more robust, you can create an extension for migrations which allows you to call CreateView.

Related

How can I run SQL script in OnModelCreating by EF Core?

My program has an existing SQLite database.
In the new version of the program, it needs to add a column for a feature.
Now the program is made by .NET 6 (WPF) and EF Core 6.
I have to detect whether the new column existed and add it or not.
Here is my code in OnModelCreating to detect the column existed or not:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var Result = Database.ExecuteSqlRaw("SELECT Count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='BindDesign' AND COLUMN_NAME='type'");
}
After the code run, it reports this error:
An attempt was made to use the model while it was being created. A DbContext instance cannot be used inside 'OnModelCreating' in any way that makes use of the model that is being created
How can I solve this? Thank you.
You should use migrations to add columns in the database.
If you want to apply migrations on startup you can check if the database needs to be migrated and apply the migration with something like this
if (_context.Database.GetPendingMigrations().Any()) {
await _context.Database.MigrateAsync();
}
Try to Use Different Context for your schema , the error message is clear , you can on use makes use of the model that is being created.
just make another context for your schema .

Entity Framework Core code-first perform additional actions when generating migrations

I want to keep a history of changes made to all of my tables generated by EF Core.
I could do this by manually creating a second model for every model I want duplicated, but I was wondering if there's any way to do this automatically somehow.
What I would want it to do is, every time a migration is generated that includes a CreateTable call, create a duplicate of the table with something like "History" appended to the name, and with an additional column relating to the original record.
I'm not sure what would be the best way to achieve this, as I'm not very experienced with ASP.NET yet. I was thinking of overriding the MigrationBuilder.CreateTable method, but I can't figure out how I'd get the actual migration builder to use my overridden method.
Note that SQL does support Temporal Tables which internally create a second table for you. It has start/end time columns instead of a single column. The database engine maintains this for you (meaning even ad hoc sql queries not through EF are properly tracked into the history table). This is part of the ANSI SQL standard so you might find this easier than rolling your own. You can read more about these on the MSFT documentation page
If I understand it correctly, you want to execute custom SQL script before running the migration.
Well, that is indeed possible.
You will generate the migration as you do now and you'll get something like this:
public partial class MyMigration: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
//auto-generated mappings
}
}
before the auto-generate call, you could insert your own SQL script like this:
public partial class MyMigration: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("CREATE TABLE Customers_History (CustomerName, City, Country)");
migrationBuilder.Sql("INSERT INTO Customers_History (CustomerName, City, Country) SELECT CustomerName, City, Country FROM Customers)");
//auto-generated mappings
}
}
This is just an example, but you can add your own SQL to match your scenario.
With this solution you are not required to create additional models.

Alter a view in EntityFramework CF with migration files

For our project, we are using the Entity Framework (Version 6) with the code first database. So, when we want to change a procedure or a table, we do that in a class and generate a Migration File to update the Database (simple Update-Database in the Paket-Manager window).
If we want to change something that didn't get a class (like a View or a procedure) we change the migration file, which will look like this as an example:
public override void Up()
{
//Some other code...
Sql("ALTER VIEW ExampleView AS Select [Endless Lines of code]");
}
When it comes to bigger views, it gets very messy very fast.
My Question is
Is there a "smart" way to update small things in a procedure or maybe a view (like changing something in the FROM Statement) without creating a whole SQL statement that counts many rows just to do that?
Not sure what would qualify as "smart", but you can remove the SQL statement clutter from your migration classes by putting them in separate files. This article explains how.

Entity framework code first migration coming up blank

I am using entity framework to attach to an existing database where I will add a few more tables. Someone on here said this is not possible and I would need to keep the new tables separate in a new database. Here is that question:
Do not create existing table during Migration
I did some more investigation and found this on MSDN:
https://msdn.microsoft.com/en-us/data/dn579398.aspx
According to this I should run an initial migration like this:
add-migration initial -ignorechanges
so I did that and that is supposed to look at the database and match it up. After I update the database, then I am supposed to add another migration without the -ignorechanges. When I do the second migration, I get this:
namespace PTEManager.Domain.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class second : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
so it is not trying to add the 2 new tables and relationships that I need. It is coming up blank. I have tried deleting the _migrationhistory table from the database and starting over but still nothing. What am I missing?
It sounds like you are adding the second migration without making any changes. What you need to do is this:
Add DBSet<ModelName> properties to your context for all existing
tables.
Create the initial migration using -ignorechanges
Add DBSet<ModelName> properties to your context for all new tables.
Create the second migration as normal.
The second migration should then contain code to create only the new tables, relationships etc. you want. It doesn't matter whether you update the database in between migrations or only once at the end.
You could try to add normal migration and modify Up/Down methods so they include only the 2 new tables.

Create table and insert data into it during EF code first migration

I'm using Entity Framework Code First with Code First migrations.
During a migration, I need to create a new table, and then insert some data into it.
So I create the table with :
CreateTable("MySchema.MyNewTable",
c => new
{
MYCOLUMNID = c.Int(nullable: false, identity: true),
MYCOLUMNNAME = c.String(),
})
.PrimaryKey(t => t.MYCOLUMNID);
Then I try to insert data with :
using (var context = new MyContext())
{
context.MyNewTableDbSet.AddOrUpdate(new[]
{
new MyNewTable
{
MYCOLUMNNAME = "Test"
}
});
context.SaveChanges();
}
But I get an error :
Invalid object name 'mySchema.MyNewTable'.
Is it possible to do what I need ? Create a table and inserto data into it in the same migration ?
I already have other migrations where I create tables or insert data into a table, but never in the same migration...
My recommendation is move that insert code to the Seed method. Migrations introduced its own Seed method on the DbMigrationsConfiguration class. This Seed method is different from the database initializer Seed method in two important ways:
It runs whenever the Update-Database PowerShell command is executed.
Unless the Migrations initializer is being used the Migrations Seed
method will not be executed when your application starts.
It must handle cases where the database already contains data because
Migrations is evolving the database rather than dropping and
recreating it.
For that last reason it is useful to use the AddOrUpdate extension method in the Seed method. AddOrUpdate can check whether or not an entity already exists in the database and then either insert a new entity if it doesn’t already exist or update the existing entity if it does exist.
So, try to run the script that you want this way:
Update-Database –TargetMigration: ScriptName
And the Seed method will do the job of inserting data.
As Julie Lerman said on her blog:
The job of AddOrUpdate is to ensure that you don’t create duplicates
when you seed data during development.
You can try this approach:
after creating table,
create another empty migration in your Package Manager Console using:
Add-Migration "MigrationName"
Then open the .cs file of that migration and, in Up() method, insert this code:
Sql("INSERT INTO MyNewTable(NyColumnName) Values('Test')");
After that, save and go back to Package Manager Console and update the database using:
Update-Database
A way to do "random" things in migrations is to use the Sql method and pass whatever SQL statement you need to perform, for example, inserting data.
This is the best approach if you want your migrations to be able to generate a complete migration SQL script, including your data operations (the Seed method can only be executed in code and won't generate any sql script).
For those who looking for EF Core solution, In the Up method, and after creating the table:
i.e: migrationBuilder.CreateTable(name: "MyTable", .....
add the following code:
migrationBuilder.InsertData(table: "MyTable", column: "MyColumn", value: "MyValue");
or
migrationBuilder.InsertData(table: "MyTable", columns: ..., values: ...);
For more information see the docs: MigrationBuilder.InsertData Method
First I run the
PM> Add-Migration MyTableInsertInto
then I got following,
**The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration MyTableInsertInto' again.
**
I have used following code for c# data migrations
public partial class MyTableInsertInto : DbMigration
{
public override void Up()
{
Sql("INSERT INTO MyNewTable(MyColumnName) Values ('Test')");
}
public override void Down()
{
Sql("DELETE MyNewTable WHERE MyColumnName= 'Test'");
}
}
Then I run following
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [202204120936266_MyNewTableInsertInto].
Applying explicit migration: 202204120936266_MyNewTableInsertInto.
Running Seed method.
After running the seed method data base is updated successfully and this works fine for me.

Categories