how to run stored procedure in Entity framework - c#

I have a Query in Database which is bringing another query in response using Json via Ajax. I have created the stored procedure which is accepting that query and bringing multiple columns.
I am not getting how to run stored procedure in entity framework.
Help needed.
Method:-
public ActionResult DropDownn(string query)
{
using (DynamicDBEntities db = new DynamicDBEntities())
{
//var dbQuery = db.Database.SqlQuery<Cust_mas>(query).ToList();
//return Json(courseList, JsonRequestBehavior.AllowGet);
}
}
SP:-
alter procedure [dbo].[SP_DynamicCtrl]
#query nvarchar(1000)
As
begin
execute sp_executesql #query;
end

As per my understanding, you want to execute a stored procedure that run on multiple tables, and then return Json Data to View. You can actually do something like below:
Approach 1: (Using ExecuteSqlCommand)
SqlParameter param1 = new SqlParameter("#query", query);
var result = db.Database.ExecuteSqlCommand("SP_DynamicCtrl #query",
param1);
Approach 2: (Using Object Type on SqlQuery)
SqlParameter param1 = new SqlParameter("#query", query);
Var result = db.Database.SqlQuery<Object>("exec SP_DynamicCtrl #query", param1);
Approach 3: (Cleaner Approach)
1.) Create a model as per your return parameters from stored procedure, let's call it YourType class.
2.) Use the below code to call stored pocedure:
SqlParameter param1 = new SqlParameter("#query", query);
Var result = db.Database.SqlQuery<YourType>("exec SP_DynamicCtrl #query", param1);
After you get the result from above query, you can convert it to JSON befor returning in controller:
return Json(result, JsonRequestBehavior.AllowGet); //Typecast the result as per your need
Please modify code as per your need.

if you have mapped it in the edmx try this
public ActionResult DropDownn(string query)
{
using (DynamicDBEntities db = new DynamicDBEntities())
{
var result = context.SP_DynamicCtrl(query);
return result.FirstOrDefault();
}
}

Related

SQL Join Stored Procedure Does Not Return List In Blazor Server

Here I have blazor server app, where I have stored procedure [dbo].[spGetAllChapter] which return list of chapter name, class name and subject name in SSMS.
To call this stored procedure [dbo].[spGetAllChapter] I have used _dbContext.Database.ExecuteSqlRaw().
Now, the problem is that on calling stored procedure it does not return list instead it shows -1 value, but on executing same stored procedure in SSMS returns list.
Below is my stored procedure
ALTER PROCEDURE [dbo].[spGetAllChapter]
AS
BEGIN
SELECT CH.ChapterId
, CH.ChapterName
, SC.ClassName
, S.SubjectName
FROM [dbo].[Chapter] AS CH
JOIN [dbo].[SchoolClass] AS SC
ON CH.SchoolClassId= SC.SchoolClassId
JOIN [dbo].[Subject] AS S
ON CH.SubjectId = S.SubjectId
END
Below is how I have called stored procedure
public eLearningDBContext _dbContext = new eLearningDBContext();
//getChapterList is -1 instead of returning list from procedure
var getChapterList = _dbContext.Database.ExecuteSqlRaw($"EXEC dbo.spGetAllChapter");
The docs for ExecuteSqlRaw say that the function:
Executes the given SQL against the database and returns the number of rows affected.
Note that it doesn't return the data, but the number of rows affected. Perhaps what you're looking for is FromSqlRaw
Alternatively, you don't need a stored procedure to accomplish what you want; you can simply project the columns you want in a regular EF query, like:
_dbContext.Chapters.Select(ch => new
{
ChapterId = ch.ChapterId,
ChapterName = ch.ChapterName,
ClassName = ch.SchoolClass.ClassName,
SubjectName = ch.Subject.SubjectName
}).ToList()
This will give you a list of anonymous objects with the fields you want, but you could also create a named type (Like ChapterAbstract or something) and project to that instead.
If the context was created DB first, you can update the DataModel via the Wizard to include Stored Procedures and Functions. Then you can call the SP directly from the context
_dbcontext.spGetAllChapter();
I some how solved by making this helper class
public static class SQLHelper
{
public static List<T> RawSqlQuery<T>(string query, Func<DbDataReader, T> function)
{
using (var context = new eLearningDBContext())
{
using (var command = context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = query;
command.CommandType = CommandType.Text;
context.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
var entities = new List<T>();
while (result.Read())
{
entities.Add(function(result));
}
return entities;
}
}
}
}
}
var list = SQLHelper.RawSqlQuery($"EXEC dbo.spGetAllChapter",
x => new ChapterVM {
ChapterId = (int)x[0],
ChapterName = (string)x[1],
ClassName = (string)x[2],
SubjectName = (string)x[3]
}).ToList();

Stored Procedure results to JSON response minimizing memory usage in C# MVC

I currently have a MVC C# web application and I am trying to create an action result that acts kind of like an API. This API method runs a stored procedure and returns the results in JSON format as the response.
Problem is, in some instances the stored procedure is returning ~6.5k rows, and all that data is coming into memory of my application and blowing it up. (there's a good bit of columns to this data, all required)
So my question is: is there a way to run a stored procedure and return its results to the client without bringing the whole result set into memory on the server? Maybe I can take the response sql stream and feed it to the response stream?
My current code contains the memory leak and is as follows:
public ActionResult GetOutletsByHierarchyLevel(string SearchTerm, string Level, bool ReturnAll = false)
{
...
var data = db.CollectionFromSql(
"EXEC [apps].[Rapport_GetOutletsByHierarchyLevel] #SearchTerm,#HierarchyLevel,#ReturnAll",
new Dictionary<string, object>
{{"#SearchTerm", SearchTerm}, {"#Level", Level}, {"#ReturnAll", ReturnAll}}
);
var jsonResult = Json(new JSONResponse()
{
Success = true,
Data = data.ToList().DynamicSQLToDictionary()
});
data = null;
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
}
Let me know if there's anything else I can supply you all with. Thanks in advance for any recommendations/articles!
Do you have code access to the stored procedure?
If yes, then you can to implement pagination on sql level: Implement paging (skip / take) functionality with this query.
I return JSON directly from my stored procedures and then return a JSON response from the API method (requires SQL Server 2016 or greater). I have written helper methods to call my stored procedures. This one calls a stored procedure with no parameters and returns a JSON array as a string:
public static string GetDataJSONArray(
string procName,
string connection = null
)
{
if (connection == null)
connection = defaultConnection;
var sql = procName;
StringBuilder sb = new StringBuilder();
using (SqlConnection sqlConnection = new SqlConnection(connection))
{
sqlConnection.Open();
SqlCommand cmd = new SqlCommand(sql, sqlConnection);
cmd.CommandTimeout = defaultTimeout;
cmd.CommandType = CommandType.StoredProcedure;
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
sb.Append(reader.GetString(0));
}
}
}
var json = sb.ToString();
if (string.IsNullOrWhiteSpace(json))
{
json = "[]";
}
return json;
}
Example proc:
create procedure GetTableRecordCounts
as
begin
select t.name TableName, i.rows RecordCount
from sysobjects t, sysindexes i
where t.xtype = 'U' and i.id = t.id and i.indid in (0,1)
order by RecordCount desc
for json path, INCLUDE_NULL_VALUES
end
go
Example API Method:
[HttpGet]
public HttpResponseMessage GetTableRecordCounts()
{
var jsonString = ProcWrapper.GetDataJSON("GetTableRecordCounts");
HttpResponseMessage success = Request.CreateResponse(HttpStatusCode.OK);
success.Content = new StringContent(jsonString, Encoding.UTF8, "application/json");
return success;
}
I don't deserialize to objects in the API method unless I need to for some reason. BTW, I currently use the approach of passing a JSON object or array as string into all my procs that need input and I always return a JSON object or array as a string if the proc needs to return a result. Therefore, my procs have a single parameter like "#JSON nvarchar(max)". I like the simplicity.

ExecuteAsync Changes Passed Dynamic Parameters Names

I am trying to insert form data to a table using a stored procedure by calling the ExecuteAsync method of Dapper. After sending the parameters names are changed.
public static async Task<bool> Insert(DynamicParameters dp)
{
int IsSuccessed;
using (SqlConnection c = new SqlConnection(con))
{
IsSuccessed = await c.ExecuteAsync("AddStudent", dp, commandType: CommandType.StoredProcedure);
}
return IsSuccessed > 0 ? true : false;
}
Parameters are changed showing in a sql server Profiler
declare #p8 nvarchar(100)
set #p8=NULL
exec AddStudent #Name1=N'Ahmad',#TazkiraNumber1=N'890',#TazkiraPage1=N'0987',#TazkiraVolume1=N'8',#GenderID1=N'1',#VisitorSourceID1=N'2',#msg=#p8 output
select #p8
The following code make a dynamic parameters from form collection:
var dp = new DynamicParameters();
foreach (string key in form.Keys)
{
dp.Add(key.ToString(), form[key]);
}
I am getting form data using IFormCollection and creating DynamicParameters from the key and value of form collection and pass the dynamic parameter to the ExecuteAsync method and it calls the stored procedure to insert the data to the tables. The process of executing the stored procedure fails.
I run the SQL server profiler and observed that 1 is appended to each parameter as #Name became #Name1.
Any idea why is this happing?
For this issue, it is caused by that, StringValues is failed to converted to the DbType.
Try code below:
foreach (string key in form.Keys)
{
dp.Add(key.ToString(), form[key].ToString());
}
In my case, it was a collection of System.Guid I was trying to pass.
var guids = new List<System.Guid>()
guids.Add(new System.Guid());//for the brevity of example
guids.Add(new System.Guid());//for the brevity of example
parameters.Add("#parameterName", guids);
I had to change the last line like below.
parameters.Add("#parameterName", string.Join(",", guids));

Count the results from Stored Procedure

The goal
Count the results returned from a stored procedure.
The problem
I have the following code on my ProductsController:
[HttpGet]
public ActionResult DailyOffers()
{
var productsList = Products.BuildOffersList();
ViewBag.Title = String.Format("Ofertas de hoje ({0:dd/MM/yyyy})",
DateTime.Now);
ViewBag.CategoryProductsQuantity = ??;
ViewBag.CurrentCategory = "Daily-Offers";
return View(productsList);
}
As you can see, there is a builder on this method. This builder returns the Stored Procedure result. And I want to count the number of results that this procedure returns.
What I'm thinking about
Maybe this?:
ViewBag.CategoryProductsQuantity = productsList.Count;
Technical details
I'm using C#.NET + MySql + Entity Framework 5 + Razor Engine.
Assuming that Products.BuildOffersList(); does in fact return a List (and not an IEnumerable/IQueryable) then what you've suggested should be fine and won't result in multiple enumerations.
ViewBag.CategoryProductsQuantity = productsList.Count();
Use parameter "output" on Stored Procedure and create parameter "out" on your method.
#ROWCOUNT INT OUTPUT
SELECT
FROM
WHERE
SET #ROWCOUNT = ##ROWCOUNT

Create Reusable Linq To SQL For Stored Procedures

I am working on a new project that needs to use Linq To SQL. I have been asked to create a generic or reusable Linq to SQL class that can be used to execute stored procedures.
In ADO.Net I knew how to do this by just passing in a string of what I wanted to execute and I could pass in different strings for each query I need to run:
SqlCommand cmd = new SqlCommand("myStoredProc", conn); // etc, etc
I am struggling with how to create something similar in Linq To SQL, if it is even possible. I have created a .dbml file and added my stored procedure to it. As a result, I can return the results using the code below:
public List<myResultsStoreProc> GetData(string connectName)
{
MyDataContext db = new MyDataContext (GetConnectionString(connectName));
var query = db.myResultsStoreProc();
return query.ToList();
}
The code works but they want me to create one method that will return whatever stored procedure I tell it to run. I have searched online and talked to colleagues about this and have been unsuccessful in finding a way to create reusable stored proc class.
So is there a way to create a reusable Linq to SQL class to execute stored procs?
Edit:
What I am looking for is if there is a way to do something like the following?
public List<string> GetData(string connectName, string procedureName)
{
MyDataContext db = new MyDataContext (GetConnectionString(connectName));
var query = db.procedureName();
return query.ToList();
}
I have reviewed the MSDN docs on Linq To Sql and these are showing the table in the IEnumerable:
IEnumerable<Customer> results = db.ExecuteQuery<Customer>(
#"select c1.custid as CustomerID, c2.custName as ContactName
from customer1 as c1, customer2 as c2
where c1.custid = c2.custid"
);
I am looking for something very generic, where I can send in a string value of the stored proc that I want to execute. If this is not possible, is there any documentation on why it cannot be done this way? I need to prove why we cannot pass a string value of the name of the procedure to execute in Linq To Sql
DataContext.ExecuteCommand is not quite what you are looking for, as it only returns an int value. What you want instead is DataContext.ExecuteQuery, which is capable of executing a stored procedure and returning a dataset.
I would create a partial class for your DBML in which to store this function.
public List<T> GetDataNoParams(string procname)
{
var query = this.ExecuteQuery<T>("Exec " + procname);
return query.ToList();
}
public List<T> GetDataParams(string procname, Object[] parameters)
{
var query = this.ExecuteQuery<T>("Exec " + procname, parameters);
return query.ToList();
}
To call a stored procedure you would do:
GetDataNoParams("myprocedurename");
or
GetDataParams("myotherprocedure {0}, {1}, {2}", DateTime.Now, "sometextValue", 12345);
or
GetDataParams("myotherprocedure var1={0}, var2={1}, var3={2}", DateTime.Now, "sometextValue", 12345);
If you want to call procedures with no return value that is easy enough too, as I'm sure you can see, by creating a new method that doesn't store/return anything.
The inspiration came from http://msdn.microsoft.com/en-us/library/bb361109(v=vs.90).aspx.
The simplest answer to your question is that you can grab the Connection property of your MyDataContext and create and execute your own SqlCommands just like you would in straight up ADO.Net. I'm not sure if that will serve your purposes, especially if you want to retrieve entities from your LINQ to SQL model.
If you want to return entities from the model, then have a look at the DataContext.ExecuteCommand method.
When we drop a Table or StoredProcedure in our .dbml file it creates its class which communicates with the data layer and our business logic.
In Linq to SQL we have to have the StoredProcedures or Tables present in the .dbml file otherwise there is no way to call a generic method in Linq to SQL for calling a stored procedure by passing its name to a method.
But in ADO.Net we can do it (like you know)
SqlCommand cmd = new SqlCommand("myStoredProc", conn);

Categories