I am using EF Core Version 3.1.9.
The code shown here is to execute a stored procedure - but it does not seem to work:
var test1 = "abc";
var test2 = "xyz";
EmpResponse emp = await _context.Emp
.FromSqlRaw("EXECUTE EMPS..sel_keys #param1 = 20000, #param2 = {0}, #param3 = {1}", test1, test2)
.FirstOrDefaultAsync();
I get this error:
FromSqlRaw or FromSqlInterpolated was called with non-composable SQL and with a query composing over it.
Consider calling AsEnumerable after the FromSqlRaw or FromSqlInterpolated method to perform the composition on the client side.
I found the below document and it suggest to modify using AsEnumerable().FirstOrDefault()
https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.x/breaking-changes#fromsql
But since I am using await, the above suggestion does not work.
Could someone suggest how to do it with await?
The simplest is to await a call to ToListAsync() and then apply {First|Single|Last}{OrDefault}, e.g.
var emp = (await _context.Emp
.FromSqlRaw("EXECUTE EMPS..sel_keys #param1 = 20000, #param2 = {0}, #param3 = {1}", test1, test2)
.ToListAsync())
.FirstOrDefault();
In general they (EF Core designers) are expecting you to just insert AsAsyncEnumerable()
var emp = await _context.Emp
.FromSqlRaw("EXECUTE EMPS..sel_keys #param1 = 20000, #param2 = {0}, #param3 = {1}", test1, test2)
.AsAsyncEnumerable() // <--
.FirstOrDefaultAsync();
but that first requires installing additionally System.Linq.Async package, and second - once you do that, you start getting a lot of ambiguous call compile-time errors when you access DbSets in queries, because they implement both IQueryable<T> and IAsyncEnumerable<T>.
So you'd better stay with the first solution until this gets resolved (I think it would be in EF Core 6).
I have created store procedure in Sql server its working.when i imliment it into my entity framework, its throws exception, I am new to this, kindly suggest
//SQL//
create procedure sp_getUserID
#deviceID int,
#userID int out
as
Begin
Select #userID= userId from UserTable
where deviceID = #deviceID
End
// C#
var UserID =0;
// This line error ERROR: //The specified parameter name '#userID' is not valid.
System.Data.Entity.Core.Objects.ObjectParameter UserOutput = new System.Data.Entity.Core.Objects.ObjectParameter("#userID", typeof(int));
var objStoredProcd = dbContext.sp_getUserID(UserOutput, UserLogin.DeviceUUID);
UserID = Convert.ToInt32(UserOutput.Value);
I'm working with Repository Pattern and EF6. What I need to do is to call a SP that delete records for mapping table that have nothing in common within the repository I'm calling the SP.
I've tried with
this.dbSet.SqlQuery("exec mySP #Param1, #Param2", param1, param2);
but this returns all the records from the DB of the current repository I'm in. It's like I've wrote "SELECT * FROM Group" (if I'm in GroupRepository).
My SP returns nothing since it's deleting some records and I already wasted 2 days of searching how to call the SP. I can give additional info if needed.
Can anybody help?
Finally I manage to execute my stored procedure, which was accepting a List<int> and an Id. The code looks like this:
SQL SERVER:
CREATE TYPE [dbo].[IntListType] AS TABLE
(
[Item] INT
);
GO
CREATE PROCEDURE [removeEventUsersFromEvents]
(
#EventIds [dbo].[IntListType] READONLY,
#UserId INT
)
AS
BEGIN
BEGIN Tran T1
DECLARE #query NVARCHAR(MAX)
SET NOCOUNT ON;
SET #query = 'DELETE FROM [EventUser]
WHERE [EventID] IN (SELECT Item from #EventIds) AND [UserID] = #UserId';
EXECUTE sp_executesql #query,
N'#EventIds [dbo].[IntListType] READONLY, #UserId INT',
#EventIds,
#UserId;
COMMIT Tran T1
END;
C#:
List<int> eventIdsToBeDeleted = this.dbSet...(geting some Ids from the db);
DataTable dt = new DataTable("IntListType");
dt.Columns.Add("Item", typeof(Int32));
eventIdsToBeDeleted.ForEach(id => dt.Rows.Add(id));
var eventIds = new SqlParameter("EventIds", SqlDbType.Structured);
eventIds.TypeName = "dbo.IntListType";
eventIds.Value = dt;
foreach (var user in usersToBeDeletedFromEvents)
{
var userId = new SqlParameter("UserId", SqlDbType.Int);
userId.Value = user.UserID;
this.Context.Database.SqlQuery(typeof(List<int>),
"EXEC removeCalendarEventUsersFromSpecificGroupAndEvents
#CalendarEventIds,
#UserProfileDetailId",
eventIds,
userId);
}
This will eventually return an empty List<int>.
I have written a procedure as following:
ALTER PROC ReturnProc
AS
BEGIN
RETURN 5
END
I am trying to get the return value from the Procedure in the following way:
com.CommandText = "ReturnProc";
com.CommandType = CommandType.StoredProcedure;
SqlParameter parameterReturnValue = new SqlParameter();
parameterReturnValue.Direction = ParameterDirection.ReturnValue;
com.Parameters.Add(parameterReturnValue);
con.Open();
tran = con.BeginTransaction();
com.Transaction = tran;
com.ExecuteNonQuery();
tran.Commit();
//Get the return value
iReturn = Convert.ToInt64(parameterReturnValue.Value);
I failed to get the return value after execution. In the real scenario, I am concatenating the parameters with the procedure, rather than adding them in SqlParameter list.
Could anybody help me on this?
I think you have to retrieve the value from the Parameters collection. See How can I get Stored Procedure return value in C#?
Lately I've been working on stored procedure and encountered 1 strange problem.
First, I was able to successfully call a stored procedure from the database via:
IList<XXXViewModel> XXXList =
_context.Database.SqlQuery("spXXX").ToList();
But when I needed to pass parameters it failed:
var parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("param1", param1Value));
parameters.Add(new SqlParameter("param2", param2Value));
IList<XXXViewModel> XXXList =
_context.Database.SqlQuery<XXXViewModel>("spXXX #param1, #param2", parameters).ToList();
And I got the ff, error:
No mapping exists from object type
System.Collections.Generic.List`1[[System.Data.SqlClient.SqlParameter,
System.Data, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089]] to a known managed provider native
type.
Note that I've also tried:
_context.Database.ExecuteSqlCommand<EXEC XXXViewModel>("spXXX #param1, #param2", parameters).ToList();
But got the same result :-(.
Also I've tried calling, by specifying each of the parameters:
IList<XXXResult> query = Context.Database.SqlQuery<XXXResult>("SP #paramA, #paramB, #paramC", new SqlParameter("paramA", "A"), new SqlParameter("paramB", "B"), new SqlParameter("paramC", "C")).ToList();
Anyone has any idea?
In case someone else comes across this...
I created the parameters as a List and then in the SqlQuery call I passed it with a .ToArray(). Worked for me. Here's the modified code below...
var parameters = new List<object>();
parameters.Add(new SqlParameter("param1", param1Value));
parameters.Add(new SqlParameter("param2", param2Value));
IList<XXXViewModel> XXXList =
_context.Database.SqlQuery<XXXViewModel>("spXXX #param1, #param2", parameters.ToArray()).ToList();
You need to pass each parameter to the method (ie You can't pass a list)
IList<XXXViewModel> XXXList =
_context.Database.SqlQuery<XXXViewModel>("spXXX #param1, #param2",
new SqlParameter("param1", param1Value),
new SqlParameter("param2", param2Value)).ToList();
The solution for this problem (in my case was)
var stuff = db.Database.SqlQuery<SomeEntityType>(query, parms);
Where query was a string that had parameters inserted such as #Name etc.
The parms variable was a List of SQLParameters. SQL doesn't like generic lists....
SQL must have an array of SQLParameters sent as and object[] and not a list of generic type.
var stuff = db.Database.SqlQuery<SomeEntityType>(query, parms.ToArray());
In my case parameter's SQL type and handling null values solved this problem. It was throwing same exception No mapping exists from object type System.RuntimeType to a known managed provider native type. for this also
var parameter1 = new SqlParameter("parameter1", typeof(string));
var parameter2 = new SqlParameter("parameter2", typeof(string));
var parameter3 = new SqlParameter("parameter3", typeof(string));
parameter1.Value = string.IsNullOrEmpty(parameter1Value) ? (object)DBNull.Value : parameter1Value;
parameter2.Value = string.IsNullOrEmpty(parameter2Value) ? (object)DBNull.Value : parameter2Value;
parameter3.Value = string.IsNullOrEmpty(parameter3Value) ? (object)DBNull.Value : parameter3Value;
http://karim-medany.blogspot.ae/2014/02/no-mapping-exists-from-object-type.html
didn't state SQL Server version, but Erland Sommarskog has an article on how to use Table-Valued Parameters in SQL Server and .NET.
http://www.sommarskog.se/arrays-in-sql-2008.html
Able to pass a variable amount of arguments from client using a single parameter.
If the stored procedure is only for update/insert, the following can be used as well.
string cmd = Constants.StoredProcs.usp_AddRoles.ToString() + " #userId, #roleIdList";
int result = db.Database
.ExecuteSqlCommand
(
cmd,
new SqlParameter("#userId", userId),
new SqlParameter("#roleIdList", roleId)
);
If you're initializing the List at the same place you can use Array instead of List
var parameters = new SqlParameter[]
{
parameters.Add(new SqlParameter("param1", param1Value));
parameters.Add(new SqlParameter("param2", param2Value));
};
IList<XXXViewModel> XXXList =
_context.Database.SqlQuery<XXXViewModel>("spXXX #param1, #param2", parameters).ToList();
If you are using dapper please check the Json serialize is properly added JsonConvert.SerializeObject(**ClassName**)
You can also use string.Format to pass parameters to a stored procedure
string command = string.Format("EXEC spXXX {0},{1}", param1Value, param2Value);
IList<XXXViewModel> XXXList =
_context.Database.SqlQuery<XXXViewModel>(command).ToList();