Pass table-valued parameter to a stored procedure - c#

In my project we are using Dapper to connect with database for operations.
I have created a stored procedure in my SQL Server database as:
CREATE PROCEDURE dbo.usp_Check
#TestTableType [dbo].[TestTableType] READONLY
AS
BEGIN
SELECT
TestTableType.BrokerNPN,
CASE WHEN Sales.BrokerNPN IS NULL THEN 0 ELSE 1 END as isBrokerNPNExist
FROM
[dbo].[tbl_Sales] Sales
LEFT JOIN
#TestTableType TestTableType ON Sales.BrokerNPN = TestTableType.BrokerNPN
END
And in C# I am trying to consume my stored procedure with a TVP like this:
public void CheckSP(List<string> ParamData)
{
using (var connection = new ConnectionProvider("DbName").GetOpenConnection())
{
var dt = new DataTable("dbo.TestTableType");
dt.Columns.Add("NPN", typeof(string));
dt.Rows.Add("12345");
// First attempt
var result = connection.Query<CheckData>("usp_Check", new { BrokerNPN = ParamData }, CommandType.StoredProcedure).ToList();
// Second attempt
var result = connection.Query<CheckData>("usp_Check", new { BrokerNPN = dt}, CommandType.StoredProcedure).ToList();
}
}
But I am not able to pass the TVP to the stored procedure.
For the first attempt, I am getting this error
Procedure or function CheckBrokerNPNExist has too many arguments specified
And for the second attempt, I cannot use pass DataTable directly.

Use the same column name in [dbo].[TestTableType] in c# code

I think you're just using a wrong name for the parameter...
See your stored procedure definition:
CREATE PROCEDURE dbo.usp_Check
#TestTableType [dbo].[TestTableType] READONLY
Your parameter is called #TestTableType - yet when you call this stored procedure from C#, you're using a different name:
var result = connection
.Query<CheckData>("usp_Check",
new { BrokerNPN = ParamData },
CommandType.StoredProcedure).ToList();
I would try to use the same name:
var result = connection
.Query<CheckData>("usp_Check",
new { TestTableType = ParamData },
CommandType.StoredProcedure).ToList();

Related

Using Dapper (C#) to call PostgreSQL stored procedure

I'm posting this for two reasons
I'm new to PostgreSQL and it took a while to piece this information together, so I thought someone else would find this helpful and
to ask if there is another way to call a PostgreSQL stored procedure that doesn't require all of the parameters to be included in the stored procedure name/signature.
The following uses Dapper and Npgsql to make a call to a PostgreSQL stored procedure that inserts (null id_inout passed in) or updates a record (id_inout has a value).
I'd like to understand why PostgreSQL requires the entire stored procedure signature when making the call.
public static int? PO_Save(PurchaseOrder po)
{
int? recordId = null;
using (var cn = new NpgsqlConnection(AppSettings.ConnectionString))
{
if (cn.State != ConnectionState.Open)
cn.Open();
var procName = "CALL po_save(#in_ponumber,#in_deliverydate,#in_bldnum," +
"#in_facname,#in_facnumber,#in_facaddress1,#in_facaddress2,#in_city," +
"#in_state,#in_zip,#in_theme,#id_inout)";
var p = new Dapper.DynamicParameters();
p.Add("#in_ponumber", po.PONumber);
p.Add("#in_deliverydate", po.DeliveryDate);
p.Add("#in_bldnum", po.BldNum);
p.Add("#in_facname", po.FacName);
p.Add("#in_facnumber", po.FacNumber);
p.Add("#in_facaddress1", po.FacAddress1);
p.Add("#in_facaddress2", po.FacAddress2);
p.Add("#in_city", po.City);
p.Add("#in_state", po.State);
p.Add("#in_zip", po.Zip);
p.Add("#in_theme", po.Theme);
p.Add("#id_out", po.POID, null, ParameterDirection.InputOutput);
var res = cn.Execute(procName, p);
recordId = p.Get<int>("#id_inout");
}
return recordId;
}
You should be able to pass commandType: CommandType.StoredProcedure to Execute, e.g:
var res = cn.Execute(
"po_save",
new {
in_ponumber = po.PONumber,
in_deliverydate = po.DeliveryDate,
// etc...
},
commandType: CommandType.StoredProcedure,
);
Here's the docs with such an example: https://github.com/StackExchange/Dapper/blob/main/Readme.md#stored-procedures
I wanted to find an answer to this myself, and beginning with Npgsql 7.0, CommandType.StoredProcedure will now invoke stored procedures and not functions as before.

Stored procedure from Oracle doesn't work with Entity Framework database-first workflow

I have a problem when I try to call a stored procedure from Oracle. I could correctly import the stored procedure which was mapped to a function which I called AddVideo, but when running this function it throws a System.ArgumentException exception that I do not know why it can be.
This is my stored procedure in Oracle:
create or replace procedure SP_ADD_VIDEO
(p_name in varchar2, p_release_date in date, p_genre in varchar2)
is
genreId number;
maxVideoId number;
begin
select G.ID into genreId
from GENRES G
where G.NAME = p_genre;
insert into VIDEOS(ID, NAME, RELEASEDATE)
values(SEQ_VIDEOS.NEXTVAL, p_name, p_release_date);
select MAX(V.ID) into maxVideoId
from VIDEOS V;
insert into VIDEOGENRES(VIDEOID,GENREID)
values(maxVideoId,genreId);
end SP_ADD_VIDEO;
And this is my mapped function:
public virtual int AddVideo(string p_NAME, Nullable<System.DateTime> p_RELEASE_DATE, string p_GENRE)
{
var p_NAMEParameter = p_NAME != null ?
new ObjectParameter("P_NAME", p_NAME) :
new ObjectParameter("P_NAME", typeof(string));
var p_RELEASE_DATEParameter = p_RELEASE_DATE.HasValue ?
new ObjectParameter("P_RELEASE_DATE", p_RELEASE_DATE) :
new ObjectParameter("P_RELEASE_DATE", typeof(System.DateTime));
var p_GENREParameter = p_GENRE != null ?
new ObjectParameter("P_GENRE", p_GENRE) :
new ObjectParameter("P_GENRE", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("AddVideo", p_NAMEParameter, p_RELEASE_DATEParameter, p_GENREParameter);
}
And this is where I call the AddVideo function to insert the given values as parameters into the stored procedure:
class Program
{
static void Main(string[] args)
{
var dbContext = new VidzyDbContext();
dbContext.AddVideo("Gladiator", DateTime.Today, "Action");
}
}
I hope someone can help me solve this problem.
I can't tell if it would work for Oracle, but in MSSQL, you'd have to do this:
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction(
"SP_ADD_VIDEO #P_NAME, #P_RELEASE_DATE, #P_GENRE",
p_NAMEParameter, p_RELEASE_DATEParameter, p_GENREParameter);
When you do create your parameters, continue not putting the # when you do new ObjectParameter... though.
I always had my parameters names with the same casing in the code as in the database, so I'm not sure if you should adjust to lowercase in the code to match the database or not.

Why is data not stored in database from stored procedure?

I'm using Entity Framework and I'm trying to store some data in SQL Server using this stored procedure:
create procedure [dbo].[Sp_OrderList]
#OrderId int,
#OrderName varchar(50),
#OrderData datetime
As
Begin
Insert into OrderList (OrderId, OrderName, OrderDate)
values (#OrderId, #OrderName, #OrderData)
End
C# code:
public HttpResponseMessage SaveCountry(OrderList cnt)
{
OrderList Cntrcountr = new OrderList();
Cntrcountr.OrderId = cnt.OrderId;
Cntrcountr.OrderName = cnt.OrderName;
Cntrcountr.OrderDate = cnt.OrderDate;
var param = new SqlParameter("",Cntrcountr);
var country = db.Database.SqlQuery<string>("Sp_OrderList", Cntrcountr);
return Request.CreateResponse(HttpStatusCode.OK, country);
}
I'm getting an error
500 Internal server error
Please help me - what's my mistake?
Since your stored procedure doesn't actually return any data you should use the ExecuteSqlCommand method. Try this:
db.Database.ExecuteSqlCommand(
"EXEC Sp_OrderList #OrderId, #OrderName, #OrderData",
new SqlParameter("#OrderId", cnt.OrderId),
new SqlParameter("#OrderName", cnt.OrderName),
new SqlParameter("#OrderData", cnt.OrderData));
Database.SqlQuery takes the sql and then parameters as an array. You are passing in a complex objects and expecting the properties to be translated into parameters. See Database.SqlQuery documentation.
public HttpResponseMessage SaveCountry(OrderList cnt)
{
var country = db.Database.SqlQuery<string>("exec Sp_OrderList #OrderId, #OrderName, #OrderData", cnt.OrderId, cnt.OrderName, cnt.OrderDate);
return Request.CreateResponse(HttpStatusCode.OK, country);
}
That said the reason for the 500 status is because your server code has experienced an unhandled Exception. You should add logging OR learn how to debug your server side code so you can inspect the Exception when it occurs.

How can I run a stored procedure that has no return values from C# with my db context?

I am using the following code to run a stored procedure:
MyContext db = new MyContext();
var a = db.Database.SqlQuery<string>("dbo.getQuestionUIdsByTopicId #TopicId",
new SqlParameter { ParameterName = "TopicId", Value = testTopicId });
This works good but now I will have a stored procedure that does not return any data other than a return code.
How can I execute a stored procedure with a parameter using my context db.Database and have the stored procedure return only a return code? If someone could give an example of a 3-4 line SP and how it returns a return code that would also be a great help.
You can use ExecuteSqlCommand to send non-query commands to the database.
int result = db.Database.ExecuteSqlCommand("exec sproc...");
See this link for more info.

how to access output values of Select instance in LINQ in a C# program

I am new to writing Stored Procedure. So I wrote below procedure and want to access the output values in my program, hot to do it.
My Stored Procedure:
Create Procedure [dbo].[STP_ExecCarInDriver_SelectByCarCode]
#CarCode nchar(10)
As
Begin
SELECT DISTINCT
[MachineName]
,[FirstName]
,[LastName]
FROM [RoadTrs].[dbo].[ViewExecCarInDriver]
WHERE [CarCode]=#CarCode
End
and try with below code to instance to MachineName,FirstName and Last Name parameters:
var Results = rt.STP_ExecCarInDriver_SelectByCarCode(txtCarCode.Text);
string MachineName= Results(0).
but it doesn't work !
if you are using LinqtoSql i would advise against using the stored proceedure at all
(they become a pain in the arse to manage imho)
instead use the data context to get the item
int carcode = 0; //input your code here
var ctx = new RoadTrsDataContext();
var item - ctx.ViewExecCarInDriver.Where(x=>x.CarCode == carcode).FirstOrDefault();
ctx.Dispose();
if(item!= null)
{
var name = item.FirstName;
}
Use following:
var Results = rt.STP_ExecCarInDriver_SelectByCarCode(txtCarCode.Text).FirstOrDefault();//Use .List() if query return more than one result.
string MachineName = Results.MachineName;
string FirstName = Results.FirstName;
string LastName = Results.LastName;

Categories

Resources