Executing Raw SQL Queries using Entity Framework
While working with Entity Framework developers mostly use LINQ to Entities to
query database. However, at times you may need to execute raw queries against
the database. A common scenario is when you wish to generate an SQL query
dynamically. Luckily, EF allows you to execute raw queries easily. This article
explains how that can be done.
In the examples discussed below it is assumed that you have entity data model
created for the Customer table of the Northwind database. The following figure
shows this model:
Let's see how SELECT and UPDATE queries can be executed against the Northwind
database using the EF context generated by the designer.
Executing SELECT queries that return entities
This technique is useful when you wish to execute a query or stored procedure
that returns entities. For example, you may wish to retrieve customers that
reside in the USA. To accomplish this task you can write the following code:
DbSqlQuery<Customer> data =
db.Customers.SqlQuery("select * from customers
where country=@p0", "USA");
foreach(var cust in data)
{
//do something with cust
}
As you can see the above code calls SqlQuery() method on the Customers DbSet.
The SqlQuery() method executes a specified SELECT query and returns the results
of that entity type (Customer in this case). The SqlQuery() method accepts two
parameters - the SELECT query to be executed and zero or more parameters. It is
always recommended to use parameters instead of string concatenation to avoid
security issues. In the above example the SELECT query has one parameter with
name @p0. The parameter names must be of the form p0, p1, p2 and so on. Index
must start from 0. The second parameter of SqlQuery() accepts parameter values
in the same sequence of the parameter names. There is an alternate technique of
supplying the parameters that is discussed later in this article.
The return value of SqlQuery() is DbSqlQuery and can be used to access /
iterate through the data returned by the query.
Executing SELECT queries that return custom types
Not just entities, you can also fetch custom types from the database. For
example, you may wish to execute a JOIN statement and retrieve the results. Or
you may need to fetch data from a table that is not included in your model at
all. Consider the following code:
DbRawSqlQuery<CustomerInfo> data =
db.Database.SqlQuery<CustomerInfo>
("select customerid,companyname,contactname,country
from customers where country=@p0", "USA");
foreach (var custinfo in data2)
{
//do something custinfo
}
Note a few changes here. In this case, SqlQuery() method is called on the
Database object rather than DbSet. This is because the query doesn't return
entities. This time SqlQuery() expects the type of the resultant objects in the
result. In this case CustomerInfo class is used and is shown below:
public class CustomerInfo
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string Country { get; set; }
}
The return type this time is DbRawSqlQuery based on CustomerInfo type. Once
the query is executed the results are loaded in CustomerInfo objects. You can
access / iterate through the results as in the previous example.
Executing action queries
To execute action queries (INSERT, UPDATE, DELETE) you use ExecuteSqlCommand()
method of the Database object. Just like SqlQuery() method, ExecuteSqlCommand()
method also takes the same two parameters. The following code fragment shows how
ExecuteSqlCommand() can be used:
string sql = "INSERT INTO CUSTOMERS
(CUSTOMERID,COMPANYNAME,CONTACTNAME,COUNTRY)
VALUES(@P0,@P1,@P2,@P3)";
List<object> parameterList = new List<object>();
parameterList.Add("AAAAA");
parameterList.Add("Company 1");
parameterList.Add("Contact 1");
parameterList.Add("USA");
object[] parameters1 = parameterList.ToArray();
int result = db.Database.ExecuteSqlCommand(sql, parameters);
This example uses slightly different approach to execute an INSERT query. The
INSERT query is stored in a string variable. Notice how the parameter names are
specified as @P0, @P1, @P2 and @P3. Instead of passing these parameters in the
ExecuteSqlCommand() method itself, a List of objects is created and parameter
values are added to it. This List is then converted to an array of objects.
Finally, ExecuteSqlCommand() is called by passing the query and the
parameters.
The return value of ExecuteSqlCommand() is an integer that reveals the number
of records affected by the query.
Alternate way of passing parameters
In all the above examples you used index based parameter naming convention.
Although that worked as expected, the parameter names such as @p1 are far from
being readable. Fortunately, you can also specify named parameters in the
queries. However, if you wish to use named parameters you must supply the
parameters in the form of SqlParameter objects. The following example shows how
this can be done.
string sql = "INSERT INTO CUSTOMERS
(CUSTOMERID,COMPANYNAME,CONTACTNAME,COUNTRY)
VALUES(@custid,@company,@contact,@country)";
List<SqlParameter> parameterList = new List<SqlParameter>();
parameterList.Add(new SqlParameter("@custid","AAAAA"));
parameterList.Add(new SqlParameter("@company", "Company 2"));
parameterList.Add(new SqlParameter("@contact", "Contact 2"));
parameterList.Add(new SqlParameter("@country", "USA"));
SqlParameter[] parameters = parameterList.ToArray();
int result = db.Database.ExecuteSqlCommand(sql, parameters);
As you can see the parameters are now specified as @custid, @company,
@contact and @country. The List of SqlParameter is then created and parameters
are added to it. Note that parameters are now defined as SqlParameter objects
that map a parameter name to its value.
That's it for this article! Keep coding!!