Stored procedures in EF 6.1.3 - c#

I'm new to Entity Framework and have ran into a problem.
I have created a stored procedure in the DB (in SMMS) and triggering from .NET works fine.
However I would like EF to feed the SP to the database if the DB is wiped (like the seed method fills in data). Also I would like to have my SP in vertion control with the rest of my codebase.
So, how do I add the SP to my project in a way that it will be created with the DB, I guess its like a migration, but with no direct connection to a model class.
Is it possible to generate a "empty" migration and then modify it to my needs? with up and down method that creates and removes the SP?

Yes it is possible to generate an empty migration and then modify it to your needs. In package manager Add-Migration "AddMyStoredProcedure"
Then in your Up method:
Sql(#"EXECUTE('CREATE PROCEDURE MyStoredProcedure...etc ");
And in your Down method:
Sql(#"EXECUTE('DROP PROCEDURE MyStoredProcedure')");
I tend to use the Sql method, but there are also CreateStoredProcedure and DropStoredProcedure methods in the DbMigration class that you may prefer

Related

What is the use of EF code-first if we can't create stored proceudres, views from it?

I have been working with EF and a code-first approach for 1 month. I learnt that other than tables, there is no direct way to create DB objects like stored procedures, views, user-defined types, etc.
Below is the only way to add stored procedures manually in Up method of migration file.
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(#"your create procedure statement");
}
In this case, does anyhow I would need to go to SQL Server Management Studio to make sure that SQL query is compiled correctly and then paste in above code line.
Also in terms of implementing security on basis on role is also not sure how to do it in EF Core code first. I am not sure why many projects are using. We are thinking to go back to traditional ADO.NET approach because of all these limitations.
Can someone please tell me why should I use EF Core code-first and how to create DB objects other than tables without help of SQL Server Management studio.
Deployment is also easier in DACPAC compare to EF Core code first.

Is there an EF Core Package Manager Console command that performs the same function as the Add-Migration <name> -IgnoreChanges command in EF6

I often target existing databases, I have all the tables mapped but the program thinks it is out of agreement with SQL Server. In EF6 I would add a migration using ignore changes then call update-database and that always worked for me. I like using this method as my understanding was the EF would not push any actual changes to the database (for example if the tables mapped weird, I had a situation where EF would completely whiff on the foreign key connections).
My question is there a similar ability in EF Core using the package manager console.
Alternatively, if the ignorechanges parameter has been deprecated, is there anyway to sync the C# models (i.e. some parameter within update-database maybe?) with the SQL Server database that guarantees no modifications from C# can be pushed to the production tables, but down stream changes can be received?
You can manually edit the generated migration C# code and comment out the contents of the Up() method to get the same effect on EF Core.

Entity Framework Core - Earlier data migrations break when models are changed

We are starting a new application with with .NET Core, EF Core and Postgres - we're really liking the migrations :-)
However, I've found a problem that I can't figure out how to work around. In some of our migrations, we use the DbContext to load records, run some business logic, and resave the records. We also run database.Context.Migrate() when the web server starts, so it always runs.
This all works fine (so far).
Unfortunately it works right up until the model is changed at a later point. Consider the following migration order:
Create Customer, Order, and OrderLine models. Add the schema migrations to load the structures
A business rule changes, so we need to set a value on the Order record based on some business logic . We create a data migration where we load the DbContext, run the code, and run SaveChangesAsync()
At this point, everything is fine.
We need to add a schema migration with a new field to the Customer record.
Here, things break. If the database has not had migration 2 applied, the Migrate() command errors as when applying migration 2, EF is trying to generate a select statement that includes the new field in 3.
I'm not sure where the problem actually is in the process though: should we not be using the DbContext in the migration (and hand-code SQL statements)? Should we be explicitly be doing projections on every record read so that we know exactly what we're doing?
Something else?
In your example, 1 and 3 are Schema Migrations and 2 is a Data Migration.
Since Entity Framework Core will generate queries based off the current models in code, and not the current state of the database, there is two options for handling Data Migrations.
Perform Data Migrations In-Order with Schema Migrations
Use something like Dapper or ADO.NET to perform data migrations based on the schema at the time the migration is written. You can get the DbConnection object from the EF Context using context.Database.GetDbConnection()
Pros: Migration code will never need to be changed
Cons: You won't get any of the benefits of EF Core
Perform Data Migrations After Schema Migrations
EF performs migrations in the ascending order of the MigrationAttribute.Id string value. EF generates this based off a timestamp when calling dotnet ef migrations add xxx. You can change this attribute to ensure Data Migrations are run after all Schema Migrations. Change the filename as well for readability so that they stay in the order they will be applied.
Pros: You get all the benefits of EF Core
Cons: If the schema changes in the future, such as removing a column referenced in the data migration, you will need to modify your migration
Example MigrationAttribute.Id change:
// change
[Migration("20191002171530_DataMigration")]
// to
[Migration("99999999000001_DataMigration")]
I faced a similar issue and landed on this question; I thought I'd share the technique I used to resolve my problem for posterity.
In my case, we had a model Something that initially had a field/database column property, but the field was deprecated because property ended up being stored elsewhere. We wrote a data migration that referenced Something.property and moved it to its new location.
We wanted to update the domain model to remove property from Something as well. However, doing so would break the typechecking in the data migration.
We must have a type that has property on it to allow the data migration to typecheck. However, we must not have property on the domain model.
The solution was to introduce MigrationDbContext, which subclasses the standard DbContext. MigrationDbContext exposes a second projection of the Somethings table, called Somethings_WithProperty. This projection is a public DbSet<SomethingWithProperty>. The SomethingWithProperty class is a record of the historical type of the model with its contemporary properties; and importantly, we only allow the Type to show up in our Migrations folder. SomethingWithProperty is stored in Migrations/HistoricalModels.
Now, my data migration acquires a MigrationDbContext from dependency injection instead of a DbContext. I can replace the reference to dbcontext.Somethings with dbcontext.Somethings_WithProperty, and the data migration can typecheck. My domain model on the other hand will never be procured from the MigrationDbContext, so the only Somethings it can get are from the Somethings DbSet, which correctly omits the property that we dropped.
A few caveats; if your DbContext constructor takes a generic DbContextOptions<MyDbContext> parameter, then to satisfy dependency injection, you will need to introduce a protected constructor on MyDbContext that takes a DbContextOptions<MigrationDbContext> parameter; the child class can invoke this in its constructor. Also, MigrationDbContext will initially be confused that two projections are mapped to the same table; in its SetupSomethingsWithProperty method you should include a foreign key referencing the natural projection to clear up the confusion.
private static void SetupSomethingsWithProperty(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Something_WithProperty>(s =>
{
s.ToTable("Somethings");
s.HasOne<Something>().WithOne().HasForeignKey<Something_WithProperty>(r => r.ID);
});
}

EntityFramework 6 Migrations for both existing and new databases?

In our software, we have a customer base with existing databases. The databases are currently accessed via EntitySpaces, but we'd like to switch to EntityFramework (v6), as EntitySpaces is no longer supported. We'd also like to make use of the migrations feature. Automatic migrations are disabled, since we only want to allow database migration to an admin user.
We generated the EF model from an existing database. It all works pretty well, but the real problem we have, is, programmatically distinguishing between existing databases that match the model but have not yet been converted to EF (missing MigrationsHistory table), and empty/new databases. Converting existing databases works well with an empty migration, but for new databases we also need a migration containing the full model. Having an initial migration in the migration chain always clashes with existing databases. Of course we could create a workaround with external SQL scripts or ADO commands, creating and populating the MigrationsHistory table. But that is something we'd like to avoid, because some of our clients use MsSql databases, some use Oracle. So we'd really like to keep the abstraction layer provided by EF.
Is there a way to get EF to handle both existing, and new databases through code-based migrations, without falling back to non-EF workarounds?
My original suggestion was to trap the exception raised by CreateTable, but it turns out this is executed in a different place so this cannot be trapped within the exception.
The simplest method of proceeding will be to use the Seed method to create your initial database if it is not present. To do this...
Starting from a blank database, add an Initial Create migration and grab the generated SQL
Add-Migration InitialCreate
Update-Database -Script
Save this script. You could add it to a resource, static file or even leave it inline in your code if you really want, it's up to you.
Delete all of the code from the InitialCreate migration (leaving it with a blank Up() and Down() function). This will allow your empty migration to be run, causing the MigrationHistory table to be generated.
In your Migration configuration class, you can query and execute SQL dynamically using context.Database.SqlQuery and context.Database.ExecuteSqlCommand. Test for the existence of your main tables, and if it's not present, execute the script generated above.
This isn't very neat, but it's simple to implement. Test it well, as the Seed method runs after EVERY migration runs, not just the initial one. This is why you need to test for the existence of a main table before you do anything.
The more complicated approach would be to write a "CreateTableIfNotExists" method for migrations, but this will involve use of Reflection to call internal methods in the DbMigration class.

Call stored procedure from LINQ (with dbcontext)

Hello everybody
With EF4, i can map a EDMX function (with "update model from database" and add a stored procedure from the list) to a linq method by using a small snippet like this
[EdmFunction("MYPROJECT.Store", "Foo")]
public Decimal Foo(Int32 Id)
{
throw new NotSupportedException("Not direct access possible, use with E-SQL or LINQ");
}
But this seems not working with EF 4.1
I see that stored procedures don't work with Code First.
I'm using DbContext, is it normal that i can't do that ?
If yes, how can i make my stored procedures working ?
Thank's by advance :-)
This is only EDMX related feature and you can't use it with DbContext API code first / fluent API without EDMX. Btw. you mean SQL function and not stored procedure because imported stored procedure results in function import and cannot be called in Linq query. Methods marked with EdmFunction states either for imported SQL functions and model defined functions.
Yes I know, SQL functions appears under the stored procedures branch in the import wizard but that is just "feature" of EDMX designer.
Because you are using database-first with DbContext API and EDMX file you should be able to use EdmFunction without any problem. I just tested it. The problem probably is that your proxy method marked with EdmFunction attribute is not static - it must be static.

Categories