How to use a SQL output parameter with FromSqlInterpolated? Or alternative - sql-server

Using ASP.Net core 3.0. my Database query works - I can get the result set (records), but how to pass/get the output parameter? Also would like to know if there's a way to get the return value.
I tried using different ways to call the SQL query and the only one I was able to get working was FromSqlInterpolated, but open to different methods.
This code works for me, but I want to pass an additional parameter that can get populated as an output parameter (which is working when I test it by calling the stored proc from within SQL Server).
var result = _context.Users
.FromSqlInterpolated($"EXEC mystoredproc {user.Username} ").AsEnumerable().FirstOrDefault();
I tried creating a variable before the call
string out1 = null;
And then including that in the call but I can't figure out the syntax and I'm not sure if it's supported with this method.
var result = _context.Users
.FromSqlInterpolated($"EXEC mystoredproc {user.Username}, OUTPUT {out1}").AsEnumerable().FirstOrDefault();
Console.WriteLine(out1);
Hoping someone can point me in the right direction - would like to know both how to use the output parameter and how to get the return value, not just the record set. Thank you.

The answer accepted does not seem to work for me.
However I finally manage to have the OUTPUT parameter work by using the following code
var p0 = new SqlParameter("#userName", {user.Username});
var p1 = new SqlParameter("#out1", System.Data.SqlDbType.NVarChar, 20) { Direction = System.Data.ParameterDirection.Output };
string out1 = null;
var result = _context.Users
.FromSqlRaw($"EXEC mystoredproc #userName, #out1 OUTPUT ", p0, p1).AsEnumerable().FirstOrDefault();
Console.WriteLine(p1.Value); // Contains the new value of the p1 parameter
Just a litte warning, the p1 value property will be changed only when the request will be executed (by an AsEnumerable, Load() or anything that forces the Sql execution)

Related

EF Core 3.1.9 - FromRawSql using stored procedures stopped working - 'The underlying reader doesn't have as many fields as expected.'

At one point using FromSqlRaw to call stored procedures worked for me. I did not change anything in the project but now calling any stored procedure using FromSqlRaw returns
The underlying reader doesn't have as many fields as expected
I removed the model from the project and performed a BUILD. Then added the model back with no luck. I reduced the model and stored procedure to return a single column, no luck.
I tried adding Microsoft.EntityFrameworkCore.Relational as a dependency, no luck. All my unit test that use FromSqlRaw to call a stored procedure return the same error and at one time they all worked.
I have received Windows updates but nothing I know about that would have affected EF Core. I have run through all internet problem solving I can find. I am starting to think I will need to use ADO as a work around but I do not want a work around when it worked for me at one point. Something changed on my machine but I am not sure what to cause this problem.
Here is my test method in case my code is messed up. It is very straight forward not much to mess up. I tried the "var" out of desperation.
[TestMethod]
public void WorkOrderBOMGridABS()
{
List<WorkOrderBOMGridABS> baseList = new List<WorkOrderBOMGridABS>();
using (WorkOrderDataContext context = new WorkOrderDataContext())
{
var param = new SqlParameter[] {
new SqlParameter() {
ParameterName = "#WorkOrderId",
SqlDbType = System.Data.SqlDbType.Int,
Direction = System.Data.ParameterDirection.Input,
Value = 38385
}
};
baseList = context.WorkOrderBOMGridABS.FromSqlRaw("[dbo].[WorkOrderBOMGridABS] #WorkOrderId", param).ToList();
//var results = context.WorkOrderBOMGridABS.FromSqlRaw("[dbo].[WorkOrderBOMGridABS] #WorkOrderId", param).ToList();
Assert.IsNotNull(baseList);
}
}
I was using an old table to get the Unit Of Measure value that had an integer ID value. I switched it to use a new table with a VARCHAR ID value. Making this change to the stored proc and model code allowed the FromRawSql to work. Not sure why because while the integer ID value was getting an integer, either 0 or number other than 0, it was a valid value for the model. Any error message I received did not mention this UnitId field. It was a pain but I am glad it is resolved. At least until the next error I run into that much is guaranteed.

Use stored procedure in c# ef

I have a stored procedure in SQL Server:
Create PROCEDURE SPLogCountInUser
(#ManegerID int)
AS
SELECT COUNT(*) AS LogDone
FROM vw_UserApprove
WHERE UserMasterID = #ManegerID AND UserState = 0
I want to use this procedure to show me the output of this stored procedure in my WPF Entity Framework.
I have a label in my WPF window that I want it to show me the out put of above procedure. My code is like this, but it does not work:
HadishDataBaseEntities database = new HadishDataBaseEntities();
var All = database.SPLogCountInUser(HadishCode.gUserID);
lbl_Log.Content = All.ToList();
What does "not work" mean? Are you getting a compilation error, a runtime exception or just an unexpected result? Please always specify this when you aska question.
And what's the return type of your SPLogCountInUser method? If it is an IEnumerable, you could set the Content property of the Label to the string representation of the first item:
HadishDataBaseEntities database = new HadishDataBaseEntities();
var All = database.SPLogCountInUser(HadishCode.gUserID).ToList();
if(All != null && All.Count > 0)
lbl_Log.Content = All[0].ToString();
You can do that like this:
HadishDataBaseEntities database = new HadishDataBaseEntities();
var All = database.Database.SqlQuery<int>("SPLogCountInUser #ManegerID", HadishCode.gUserID);
lbl_Log.Content = All.First(); //Your stored procedure will always return one row, so we don't need ToList(), additionally the label will not show the actual value if you set its content to a List.
I think .ToList(); must be added if you want your SP get some meanful value.
I made such mistake by missing .ToList() and failed to get anything even though I know the SQL invoke is correct.
But after adding .ToList(); then return value is a List and you can find your value.

Interception not working as expected with Entity Framework 6

I'm trying to follow the interception example shown here to get it working with EF 6 but running into a problem with the function RewriteFullTextQuery as shown in Figure 1. The interception seems to work but it does not actually execute the logic in the for loop of the RewriteFullTextQuery method because the cmd.Parameters.Count is always zero. Furthermore the cmd.CommandText property seems to be displaying the correct SQL query which I take as another piece of evidence that the interception is working correctly.
Figure 1: RewriteFullTextQuery Code Excerpt
public static void RewriteFullTextQuery(DbCommand cmd)
{
string text = cmd.CommandText;
for (int i = 0; i < cmd.Parameters.Count; i++)
{
DbParameter parameter = cmd.Parameters[i];
if (parameter.DbType.In(DbType.String, DbType.AnsiString, DbType.StringFixedLength, DbType.AnsiStringFixedLength))
{
The RewriteFullTextQuery function is being called by the ReaderExecuting function shown in Figure 2 which gives it the command argument that is causing all the trouble.
Figure 2: ReaderExecuting Function
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
RewriteFullTextQuery(command);
}
Even though my code isn't exactly the same as the example, the interception seems to be working so it is making me wonder what conditions is it that will populate the command to have a Parameters.Count of more than zero?
It works only if you pass the parameter to the query as a variable. If you use a literal EF won't use parameters.
I mean, this won't generate any parameter
context.Notes.Where(_ => _.NoteText == "CompareValue").Count();
This will
string compareValue = "CompareValue";
context.Notes.Where(_ => _.NoteText == compareValue).Count();
It turns out that it is because of the way Entity Framework generates the SQL. If you pass in a string literal as your search value to your LINQ statement it does not generate a SQL that makes use of a parameter. But if you pass in your search value as a variable, it will generate the SQL that utilizes a parameter. A solution (for dynamic queries) and more details can be found on this blog.

MiniProfiler - SqlParameter

I am using the latest version of the MiniProfiler, everything is setup and working as I would expect. My only issue is that SqlParameters are not being displayed.
For example, I am running a stored procedure:-
var cmd = dbcon.CreateCommand();
cmd.CommandText = "USP_Admin_Subscription_List";
cmd.CommandType = CommandType.StoredProcedure;
// parameters
cmd.Parameters.Add(new SqlParameter("#UserRef", SqlDbType.NVarChar) { Value = customerRef });
When this executes I see the SQL in the MiniProfiler display but I do not see the Parameter #UserRef nor it's value.
Is this possible? It would be great to see the value so I can ensure the correct value is being passed.
I am using MVC 3
Any advice would be welcomed.
Cheers,
J
Old questions, but just in case anyone else is looking for the answer to this:
The sample code has:
// different RDBMS have different ways of declaring sql parameters - SQLite can understand inline sql parameters just fine
// by default, sql parameters won't be displayed
MiniProfiler.Settings.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
You need to change it to:
MiniProfiler.Settings.SqlFormatter = new StackExchange.Profiling.SqlFormatters.SqlServerFormatter();
And your parameters will appear.

RIA Services - Silverlight 4.0 - Accessing entities from code

I have strange situation I have simple project to test RIA functionality in Silverlight 4.0.
When I use data source for Domain Service it works great but when I want to access Context from code and execute simple query I returns 0 rows.
//test One with query provided to DataSource
var q = ctx.GetDoctorsWithPatientsAndHospitalQuery();
var result = ctx.Load(q);
//test Two using EntityQuery
EntityQuery<Doctor> query =
from c in ctx.GetDoctorsWithPatientsAndHospitalQuery()
select c;
LoadOperation<Doctor> loadOp = this.ctx.Load(query);
var result2 = loadOp.Entities;
//test Three using only entity and Linq
var result3 = ctx.Doctors.ToList();
Strange is also that when I want to add new entity instance from code it works great.
Doctor newDoctor = new Doctor()
{
FirstName = firstNameTextBoxNew.Text,
LastName = lastNameTextBoxNew.Text,
Hospital_Id = tmp,
Hospital = tmpH
};
ctx.Doctors.Add(newDoctor);
ctx.SubmitChanges();
Can anyone could point me what I have done wrong to execute select from code?
Regards,
Daniel SkowroĊ„ski
Calling "LoadOperation loadOp = this.ctx.Load(query);" from code is an async operation so you are basically checking the result before it completes.
If you want to see the results, you need to provide a callback, to the Load() method, that will execute after the data is loaded.
Data sources for domain services handle async updates, so keep propagating changes as and when load operations complete.
Your "save" works as it does not wait around for the result. You are manually checking the database afterwards. Not checking it in code.
Hope this helps.
As a quick check, try this (breakpoint on the "result2 =" line). Your loadOp is redundant in this example, but I did not want to change your code too much:
LoadOperation<Doctor> loadOp = this.ctx.Load(query, loadOperation =>
{
var result2 = loadOp.Entities;
}, null);
**Note: for those that want to edit this code... Please don't. I wanted to retain the flavour of the asker's code. loadOp and loadOperation point to the same object and result2 was the asker's choice of variable name.*

Resources