Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF 6 Migration: How to execute sql SELECT?

In our project we have necessity of adding some predefined data to DB. I think the best way and concept is using for that EF Migrations (not Seed method).

But we have a big troubles with adding related data to DB:

For Example:

Suppose we have 2 tables:

Users:

  • Id (PK auto increment)
  • Name
  • RoleId

Roles:

  • Id (PK auto increment)
  • Name

Let's suppose that we need to add User(Name = 'John', RoleId = (Id of role that name is 'Admin')).

How can we do it? It would be great if we find a solution that allows us to execute pure SQL SELECT script which not uses Entities of Code First because they can be modified or removed.

For DELETE, INSERT, UPDATE can be used Sql(...) method but what about SELECT?

like image 467
pryabov Avatar asked Feb 15 '14 15:02

pryabov


People also ask

Which of the following executes a raw SQL query to the database in EF 6?

Entity Framework Core provides the DbSet. FromSql() method to execute raw SQL queries for the underlying database and get the results as entity objects. The following example demonstrates executing a raw SQL query to MS SQL Server database. var context = new SchoolContext(); var students = context.

How do I run a raw SQL query using DbContext?

From the DbContext 's database object, create the Db command. Then, assign all the required parameters to the command object like the SQL, Command Type, SQL parameters, use existing DB transition, and optional command timeout to the command. Finally, calling ExecuteNonQuery() to execute the raw SQL query.

How do you execute migration?

Open the Package Manager Console from Tools → Library Package Manager → Package Manager Console and then run the enable-migrations command (make sure that the default project is the project where your context class is).


2 Answers

You cannot have a context into the migration.

Logically first are ran the migrations to Update the DB Schema, then you can have a context to work with the data via it. If your DB does not match the model, or even the table is still not there, you cannot use it in EF.

I had to look into the EF code (and also because was curious). Practically the Sql() method in the DbMigration class in several levels below just adds the SQL string into a list of queries that should be executed into the transaction and moves on. It does not executes it when it is called. So in short EF just fills in a list of codes lines that should be executed in the end at once. And it seems correct if you try to walk in all paths of what you can do with the C# code in the migration code.

The question is quite good actually, unfortunately still I didn't found any better solution rather than using pure ADO.

Another option is to generate more custom SQL queries, and use T-SQL more widely. For your case as you want to insert the user and set the groupId looking by the name, it can be used with inner select:

INSERT INTO Users (Name, GroupId)
VALUES ('John', RoleId = (SELECT Id FROM Roles WHERE Name = 'Admin')).

For my issue, I had to a bit do more sophisticated execution - the following does the same as the AddOrUpdate method of the DbSet, using the IF statement:

IF EXISTS (SELECT * FROM Table1 WHERE Column1='SomeValue')
    UPDATE Table1 SET (...) WHERE Column1='SomeValue'
ELSE
    INSERT INTO Table1 VALUES (...)

I found it here: http://blogs.msdn.com/b/miah/archive/2008/02/17/sql-if-exists-update-else-insert.aspx

like image 111
Vasil Popov Avatar answered Oct 18 '22 09:10

Vasil Popov


I'm using good old LINQ for this:

public override void Up()
{
    using (var dc = new DbContext("your connection string or name"))
    {
        var ids = dc.Database.SqlQuery<int>("SELECT id FROM sometable WHERE somefield={0}", 42).ToArray();

        ...
    }
}

Using LINQ is better, even for usual migrations, because, there is a bug in DbMigration.Sql method, it ignores arguments: How to pass parameters to DbMigration.Sql() Method

like image 32
omikad Avatar answered Oct 18 '22 09:10

omikad