How to call Stored Procedure in Entity Framework 6 (Code-First)?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


How to call Stored Procedure in Entity Framework 6 (Code-First)?



I am very new to Entity Framework 6 and I want to implement stored procedures in my project. I have a stored procedure as follows:


ALTER PROCEDURE [dbo].[insert_department]
@Name [varchar](100)
AS
BEGIN
INSERT [dbo].[Departments]([Name])
VALUES (@Name)

DECLARE @DeptId int

SELECT @DeptId = [DeptId]
FROM [dbo].[Departments]
WHERE @@ROWCOUNT > 0 AND [DeptId] = SCOPE_IDENTITY()

SELECT t0.[DeptId]
FROM [dbo].[Departments] AS t0
WHERE @@ROWCOUNT > 0 AND t0.[DeptId] = @DeptId
END



Department class:


Department


public class Department
{
public int DepartmentId { get; set; }
public string Name { get; set; }
}

modelBuilder
.Entity<Department>()
.MapToStoredProcedures(s =>
s.Update(u => u.HasName("modify_department")
.Parameter(b => b.Department, "department_id")
.Parameter(b => b.Name, "department_name"))
.Delete(d => d.HasName("delete_department")
.Parameter(b => b.DepartmentId, "department_id"))
.Insert(i => i.HasName("insert_department")
.Parameter(b => b.Name, "department_name")));

protected void btnSave_Click(object sender, EventArgs e)
{
string department = txtDepartment.text.trim();

// here I want to call the stored procedure to insert values
}



My problem is: how can I call the stored procedure and pass parameters into it?




16 Answers
16



You can call a stored procedure in your DbContext class as follows.


DbContext


this.Database.SqlQuery<YourEntityType>("storedProcedureName",params);



Here is an example on how to call a stored procedure with input and output parameters and that it returns a FormularioVentasTO (YourEntityType)


public FormularioVentasTO GetFormularioVentas(string idUsuario, string idFormulario)
{
FormularioVentasTO formVentas;
string sqlQuery;
SqlParameter sqlParams;

formVentas = null;

try
{
sqlQuery = "sp_ConsultarSolicitud @idUsuario, @idSolicitud, codError";

sqlParams = new SqlParameter
{
new SqlParameter { ParameterName = "@idUsuario", Value =idUsuario , Direction = System.Data.ParameterDirection.Input},
new SqlParameter { ParameterName = "@idSolicitud", Value =idFormulario, Direction = System.Data.ParameterDirection.Input },
new SqlParameter { ParameterName = "@codError", Value =-99, Direction = System.Data.ParameterDirection.Output },
};

using (PortalFinandinaPriv dbContext = new PortalFinandinaPriv())
{
formVentas = dbContext.Database.SqlQuery<FormularioVentasTO>(sqlQuery, sqlParams).SingleOrDefault();
}
}
catch (Exception ex)
{
//handle, Log or throw exception
}

return formVentas;
}



If your stored procedure returns multiple result sets as in your sample code, then you can see this helpful article on MSDN



Stored Procedures with Multiple Result Sets





Thanks @Alborz. can you please provide me some links regarding various implementation of Stored Procedure in Entity Framework 6 Code First. I searched everywhere on the web but didn't get any article where i can directly call a stored procedure for IN and OUT parameters. Thanks for your valuable time.
– Jaan
Jan 3 '14 at 20:21





This article maybe helpful blogs.msdn.com/b/diego/archive/2012/01/10/…
– Alborz
Jan 3 '14 at 20:33







This doesn't appear to work with parameters. It seems to need to explicitly list the parameters as part of the query.
– Mark
Apr 14 '15 at 14:49





Yes you do need to specify the params as part of the query - "storedProcedureName @param1, @param2". Also the type of params is System.Data.SqlClient.SqlParameter.
– Oppa Gingham Style
May 13 '15 at 0:41


"storedProcedureName @param1, @param2"


params


System.Data.SqlClient.SqlParameter





this.Database.SqlQuery<YourEntityType>("storedProcedureName @param1", new System.Data.SqlClient.SqlParameter("@param1", YourParam));
– Ppp
May 5 '17 at 4:19


this.Database.SqlQuery<YourEntityType>("storedProcedureName @param1", new System.Data.SqlClient.SqlParameter("@param1", YourParam));



All you have to do is create an object that has the same property names as the results returned by the stored procedure. For the following stored procedure:


CREATE PROCEDURE [dbo].[GetResultsForCampaign]
@ClientId int
AS
BEGIN
SET NOCOUNT ON;

SELECT AgeGroup, Gender, Payout
FROM IntegrationResult
WHERE ClientId = @ClientId
END



create a class that looks like:


public class ResultForCampaign
{
public string AgeGroup { get; set; }

public string Gender { get; set; }

public decimal Payout { get; set; }
}



and then call the procedure by doing the following:


using(var context = new DatabaseContext())
{
var clientIdParameter = new SqlParameter("@ClientId", 4);

var result = context.Database
.SqlQuery<ResultForCampaign>("GetResultsForCampaign @ClientId", clientIdParameter)
.ToList();
}



The result will contain a list of ResultForCampaign objects. You can call SqlQuery using as many parameters as needed.


ResultForCampaign


SqlQuery





For one off situations, this would work great. I find that the SProc definition should be tightly coupled with the class that inherits from DBContext, instead of out in the "wheat fields" of the product.
– GoldBishop
Jul 22 '16 at 17:17



I solved it with ExecuteSqlCommand


ExecuteSqlCommand



Put your own method like mine in DbContext as your own instances:


public void addmessage(<yourEntity> _msg)
{
var date = new SqlParameter("@date", _msg.MDate);
var subject = new SqlParameter("@subject", _msg.MSubject);
var body = new SqlParameter("@body", _msg.MBody);
var fid = new SqlParameter("@fid", _msg.FID);
this.Database.ExecuteSqlCommand("exec messageinsert @Date , @Subject , @Body , @Fid", date,subject,body,fid);
}



so you can have a method in your code-behind like this :


[WebMethod] //this method is static and i use web method because i call this method from client side
public static void AddMessage(string Date, string Subject, string Body, string Follower, string Department)
{
int resault;
try
{
using (DBContex reposit = new DBContex())
{
msge <yourEntity> Newmsg = new msge();
Newmsg.MDate = Date;
Newmsg.MSubject = Subject.Trim();
Newmsg.MBody = Body.Trim();
Newmsg.FID= 5;
reposit.addmessage(Newmsg);
}
}
catch (Exception)
{
throw;
}
}



this is my SP :


Create PROCEDURE dbo.MessageInsert

@Date nchar["size"],
@Subject nchar["size"],
@Body nchar["size"],
@Fid int
AS
insert into Msg (MDate,MSubject,MBody,FID) values (@Date,@Subject,@Body,@Fid)
RETURN



hope helped you





You need to specify a length on the nchar parameters to your stored procedure - otherwise they are just one character long, as you've found.
– Dave W
Jul 22 '14 at 8:41





sure , what a silly mistake , thanks ..
– Mahdi ghafoorian
Sep 24 '14 at 12:50





@Mahdighafoorian This is a very useful answer, thanks alot! :)
– Komengem
Mar 6 '15 at 18:30





This syntax requires no modification to the order of the SProc's Parameters, in other words Ordinal Positioning.
– GoldBishop
Oct 16 '15 at 12:52



Using your example, here are two ways to accomplish this:



1 - Use Stored procedure mapping



Note that this code will work with or without mapping. If you turn off mapping on the entity, EF will generate an insert + select statement.


protected void btnSave_Click(object sender, EventArgs e)
{
using (var db = DepartmentContext() )
{
var department = new Department();

department.Name = txtDepartment.text.trim();

db.Departments.add(department);
db.SaveChanges();

// EF will populate department.DepartmentId
int departmentID = department.DepartmentId;
}
}



2 - Call the stored procedure directly


protected void btnSave_Click(object sender, EventArgs e)
{
using (var db = DepartmentContext() )
{
var name = new SqlParameter("@name, txtDepartment.text.trim());

//to get this to work, you will need to change your select inside dbo.insert_department to include name in the resultset
var department = db.Database.SqlQuery<Department>("dbo.insert_department @name", name).SingleOrDefault();

//alternately, you can invoke SqlQuery on the DbSet itself:
//var department = db.Departments.SqlQuery("dbo.insert_department @name", name).SingleOrDefault();

int departmentID = department.DepartmentId;
}
}



I recommend using the first approach, as you can work with the department object directly and not have to create a bunch of SqlParameter objects.





Be careful, is the second example the change is not tracked by the dbContext
– edtruant
Apr 19 '16 at 9:57





EDIT.Use the System.Data.Entity.DbSet<TEntity>.SqlQuery(String, Object) instead.
– edtruant
Apr 19 '16 at 10:03





@edtruant The dbContext does appear to track the change. To test, I looked at db.<DbSet>.Count() before and after the insert statement. In both methods, the count increased by one. For completeness I added the alternate method to the example.
– Brian Vander Plaats
Apr 19 '16 at 14:46





I don't see any reference to the stored procedure in the first example.
– xr280xr
Sep 28 '17 at 14:43





@xr280xr the insert_department is referenced in the modelBuilder expression in the OP's question. That's the advantage to mapping things this way because it effectively functions the same way as if you were letting EF generate the insert/update/delete statements
– Brian Vander Plaats
Sep 28 '17 at 21:00



You are using MapToStoredProcedures() which indicates that you are mapping your entities to stored procedures, when doing this you need to let go of the fact that there is a stored procedure and use the context as normal.
Something like this (written into the browser so not tested)


MapToStoredProcedures()


context


using(MyContext context = new MyContext())
{
Department department = new Department()
{
Name = txtDepartment.text.trim()
};
context.Set<Department>().Add(department);
}



If all you really trying to do is call a stored procedure directly then use SqlQuery


SqlQuery





Thanks qujck. But i want to use stored procedure. I have given just a sample code for convenient to understand.
– Jaan
Jan 3 '14 at 15:02





@Jaan - The code above will use the stored procedure. Do you mean you want to directly call the stored procedure?
– qujck
Jan 3 '14 at 15:03





yes. Can you please tell me which way is the better. Calling directly the stored procedure or the above code you have given?
– Jaan
Jan 3 '14 at 15:15





@Jaan use the code I have shown - the ORM is meant to hide the underlying implementation - using the code above ensures that it doesn't matter to the rest of your code whether there's a stored procedure or not. You can even change the model mapping to another stored procedure or to not be a stored procedure without changing anything else.
– qujck
Jan 3 '14 at 15:18







@Chazt3n The question shows the stored procedures being configured from the line .MapToStoredProcedures(s => . A call to Add should resolve to .Insert(i => i.HasName("insert_department")
– qujck
Apr 16 '15 at 13:12


.MapToStoredProcedures(s =>


Add


.Insert(i => i.HasName("insert_department")



You can now also use a convention I created which enables invoking stored procedures (including stored procedures returning multiple resultsets), TVFs and scalar UDFs natively from EF.



Until Entity Framework 6.1 was released store functions (i.e. Table Valued Functions and Stored Procedures) could be used in EF only when doing Database First. There were some workarounds which made it possible to invoke store functions in Code First apps but you still could not use TVFs in Linq queries which was one of the biggest limitations. In EF 6.1 the mapping API was made public which (along with some additional tweaks) made it possible to use store functions in your Code First apps.



Read more



I pushed quite hard for the past two weeks and here it is – the beta version of the convention that enables using store functions (i.e. stored procedures, table valued functions etc.) in applications that use Code First approach and Entity Framework 6.1.1 (or newer). I am more than happy with the fixes and new features that are included in this release.



Read more.





Actually since 4.0, you could execute SProcs without the Model. You needed to execute Raw SQL statements instead of object property. Even with 6.1.x, you have to use either SqlQuery<T> or ExecuteSqlCommand to obtain a similar effect.
– GoldBishop
Jul 22 '16 at 17:18





This works for me by pulling back data from a stored procedure while passing in a parameter.


var param = new SqlParameter("@datetime", combinedTime);
var result =
_db.Database.SqlQuery<QAList>("dbo.GetQAListByDateTime @datetime", param).ToList();



_db is the dbContext


_db



Take a look to this link that shows how works the mapping of EF 6 with Stored Procedures to make an Insert, Update and Delete: http://msdn.microsoft.com/en-us/data/dn468673



Addition



Here is a great example to call a stored procedure from Code First:



Lets say you have to execute an Stored Procedure with a single parameter, and that Stored Procedure returns a set of data that match with the Entity States, so we will have this:


var countryIso = "AR"; //Argentina

var statesFromArgentina = context.Countries.SqlQuery(
"dbo.GetStatesFromCountry @p0", countryIso
);



Now lets say that we whant to execute another stored procedure with two parameters:


var countryIso = "AR"; //Argentina
var stateIso = "RN"; //Río Negro

var citiesFromRioNegro = context.States.SqlQuery(
"dbo.GetCitiesFromState @p0, @p1", countryIso, stateIso
);



Notice that we are using index-based naming for parameters. This is because Entity Framework will wrap these parameters up as DbParameter objects fro you to avoid any SQL injection issues.



Hope this example helps!


object xparams = {
new SqlParameter("@ParametterWithNummvalue", DBNull.Value),
new SqlParameter("@In_Parameter", "Value"),
new SqlParameter("@Out_Parameter", SqlDbType.Int) {Direction = ParameterDirection.Output}};

YourDbContext.Database.ExecuteSqlCommand("exec StoreProcedure_Name @ParametterWithNummvalue, @In_Parameter, @Out_Parameter", xparams);
var ReturnValue = ((SqlParameter)params[2]).Value;





params is an identifier use a different name.
– yogihosting
Jun 23 '16 at 13:30





The SaveChanges() here isn't necessary. Changes are committed at the ExecuteSqlCommand() call.
– Xavier Poinas
Aug 18 '16 at 9:27


public IList<Models.StandardRecipeDetail> GetRequisitionDetailBySearchCriteria(Guid subGroupItemId, Guid groupItemId)
{
var query = this.UnitOfWork.Context.Database.SqlQuery<Models.StandardRecipeDetail>("SP_GetRequisitionDetailBySearchCriteria @SubGroupItemId,@GroupItemId",
new System.Data.SqlClient.SqlParameter("@SubGroupItemId", subGroupItemId),
new System.Data.SqlClient.SqlParameter("@GroupItemId", groupItemId));
return query.ToList();
}



It work for me at code first. It return a list with matching property of view model(StudentChapterCompletionViewModel)


var studentIdParameter = new SqlParameter
{
ParameterName = "studentId",
Direction = ParameterDirection.Input,
SqlDbType = SqlDbType.BigInt,
Value = studentId
};

var results = Context.Database.SqlQuery<StudentChapterCompletionViewModel>(
"exec dbo.sp_StudentComplettion @studentId",
studentIdParameter
).ToList();



Updated for Context



Context is the instance of the class that Inherit DbContext like below.


public class ApplicationDbContext : DbContext
{
public DbSet<City> City { get; set; }
}

var Context = new ApplicationDbContext();





Hi, I can't find this Context.Database.SqlQuery<Model> , where as I can do this Context.TableName.SqlQuery(ProcName). which is giving me issues
– Marshall
Jul 12 at 14:26





@Marshall, maybe you are using the database first design. please check this link stackoverflow.com/questions/11792018/…
– reza.cse08
Jul 12 at 18:36



Mindless passenger has a project that allows for multiple results sets to be returned from a stored proc using entity framework. One of his examples below....


using (testentities te = new testentities())
{
//-------------------------------------------------------------
// Simple stored proc
//-------------------------------------------------------------
var parms1 = new testone() { inparm = "abcd" };
var results1 = te.CallStoredProc<testone>(te.testoneproc, parms1);
var r1 = results1.ToList<TestOneResultSet>();
}



if you wanna pass table params into stored procedure, you must necessary set TypeName property for your table params.


SqlParameter codesParam = new SqlParameter(CODES_PARAM, SqlDbType.Structured);
SqlParameter factoriesParam = new SqlParameter(FACTORIES_PARAM, SqlDbType.Structured);

codesParam.Value = tbCodes;
codesParam.TypeName = "[dbo].[MES_CodesType]";
factoriesParam.Value = tbfactories;
factoriesParam.TypeName = "[dbo].[MES_FactoriesType]";


var list = _context.Database.SqlQuery<MESGoodsRemain>($"{SP_NAME} {CODES_PARAM}, {FACTORIES_PARAM}"
, new SqlParameter {
codesParam,
factoriesParam
}
).ToList();



This is what EF (DB first) generates in the DbContext class:


public ObjectResult<int> Insert_Department(string department)
{
var departmentParameter = new ObjectParameter("department", department);

return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<int>("insert_department", departmentParameter);
}



When EDMX create this time if you select stored procedured in table select option then just call store procedured using procedured name...


var num1 = 1;
var num2 = 2;

var result = context.proc_name(num1,num2).tolist();// list or single you get here.. using same thing you can call insert,update or delete procedured.



This post cound help you:



Execute Stored Procedure using DBContext






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Visual Studio Code: How to configure includePath for better IntelliSense results

Spring cloud config client Could not locate PropertySource

Regex - How to capture all iterations of a repeating pattern?