How to create web Api execute stored procedure - asp.net-mvc-4

I work on SQL server 2012 and web API entity framework .NET core 2.2
so I face issue I can't implement web API execute stored Procedure below
Create proc ItemCalculateStock
#ItemId int = NULL,
#InventoryLocation int=NULL
as
begin
SELECT i.itemName,l.InventoryName, SUM(case when QTY > 0 then QTY else 0 end) as PurchasedItem,SUM(case when QTY < 0 then -QTY else 0 end) as ConsumItems,SUM(case when QTY > 0 then QTY else 0 end) + SUM(case when QTY < 0 then QTY else 0 end) as remaining
FROM [dbo].[Invenroty] n with(nolock)
inner join [dbo].[InventoryLocations] l with(nolock) on l.id=n.InventoryLocID
inner join [dbo].[Items] i with(nolock) on n.itemid=i.id
inner join [dbo].[TransactionTypes] t with(nolock) on n.transactionTypeId=t.ID and InventoryLocID=case when #InventoryLocation is null then n.InventoryLocID else #InventoryLocation end
and i.id=case when #ItemId is null then n.itemid else #ItemId end
GROUP BY i.itemName,l.InventoryName
end
so How to get result of stored procedure on web API using Entity Framework .NET core 2.2
[HttpGet("CalculateInventoryData")]
public IActionResult CalculateInventoryData([FromQuery]int optionId, [FromQuery] int ItemId, [FromQuery] int InventoryLocation)
{
// here how to get stored procedure result here
// so i ask question to know how to get result of stored procedure above
}
to call API I use the link below :
https://localhost:44374/api/Inventory/getInventoryData?optionId=1&ItemId=2&InventoryLocation=1
updated Post
I try below
context.Database.ExecuteSqlCommand("ItemCalculateStock #OptionId ,#ItemId,#InventoryLocation ", parameters: new[] {optionId,ItemId,InventoryLocation});
i get error cannot implicitly convert type int into to Microsoft .aspnetcore.mvc.action result
so how to solve issue

The code to execute a stored procedure without parameters is as follows:
SqlConnection conn=new SqlConnection(“connectionString”);
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand();
da.SelectCommand.Connection = conn;
da.SelectCommand.CommandText = "NameOfProcedure";
da.SelectCommand.CommandType = CommandType.StoredProcedure;
The code to execute a stored procedure with parameters is as follows (we can declare the function that calls the stored procedure as ExeProcedure(string inputdate)):
param = new SqlParameter("#ParameterName", SqlDbType.DateTime);
param.Direction = ParameterDirection.Input;
param.Value = Convert.ToDateTime(inputdate);
da.SelectCommand.Parameters.Add(param);
This adds an input parameter. If you need to add output parameters:
param = new SqlParameter("#ParameterName", SqlDbType.DateTime);
param.Direction = ParameterDirection.Output;
param.Value = Convert.ToDateTime(inputdate);
da.SelectCommand.Parameters.Add(param);
To get the return value of the stored procedure:
param = new SqlParameter("#ParameterName", SqlDbType.DateTime);
param.Direction = ParameterDirection.ReturnValue;
param.Value = Convert.ToDateTime(inputdate);
da.SelectCommand.Parameters.Add(param);
For more information, please refer to this post:How to run stored procedures in Entity Framework Core?

Related

Problem in updating database with relationship one to many

I'm trying to update my database but I'm getting this error:
System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Data.OleDb.OleDbException: You cannot add or change a record because a related record is required in table 'ItemTypes'.
I'm not sure how to fix it.
I don't know what i need to show so I will just show most of everything.
I've tried to look for a solution and the solutions that I've found said that it's because I'm trying to update the field with a value that is different but I don't understand why because the field is suppose to be the same.
The databases I have the problem with
This is the html part:
<asp:DropDownList ID="ItemType" runat="server">
<asp:ListItem></asp:ListItem>
</asp:DropDownList></td>
This is my code at the PageLoad:
if (!Page.IsPostBack)
{
DataTable dtItem = s.GetItemByIdForUser(Session["ItemCode"].ToString(),Session["Name"].ToString());
ItemCode.Text = dtItem.Rows[0][0].ToString();
ItemName.Text = dtItem.Rows[0][1].ToString();
ItemDes.Text = dtItem.Rows[0][2].ToString();
DataTable Types = s.GetAllItemsTypes();
for (int i = 0; i < Types.Rows.Count; i++)
ItemType.Items.Add(Types.Rows[i][0].ToString());
ItemType.SelectedItem.Text = dtItem.Rows[0][3].ToString();
ItemPrice.Text = dtItem.Rows[0][4].ToString();
Stock.Text = dtItem.Rows[0][5].ToString();
SellerName.Text = dtItem.Rows[0][6].ToString();
Image1.ImageUrl = "~/ProjectPictures/" + dtItem.Rows[0][8].ToString();
}
This is my code that happens when i click at the update:
DataTable dtItem = s.GetItemByIdForUser(Session["ItemCode"].ToString(), Session["Name"].ToString());
i.ItemCode = ItemCode.Text;
i.Name = ItemName.Text;
i.Des = ItemDes.Text;
i.Type = ItemType.SelectedItem.ToString();
i.Price = ItemPrice.Text;
i.Stock = Stock.Text;
i.UserName = SellerName.Text;
if (Pic.HasFile)
{
Pic.SaveAs(Server.MapPath("ProjectPictures/") + Pic.FileName);
i.Pic = Pic.FileName;
}
else
{
i.Pic = dtItem.Rows[0][8].ToString();
}
s.UpdateItem(i, ItemCode.Text);
Session["ItemCode"] = null;
Response.Redirect("Main.aspx");
and this is the sql sentence
string sql = "UPDATE [Items] SET [ItemName]= '#p1' , [ItemDes] = '#p2' , [ItemType] = '#p3' , [Price] = '#p4' , [Stock] = '#p5', [ItemPic] = '#p6' where [ItemCode] = '" +itemCode+ "'";
OleDbCommand cmd = new OleDbCommand(sql);
cmd.Parameters.Add(new OleDbParameter("#p1", OleDbType.VarChar));
cmd.Parameters["#p1"].Value = i.Name;
cmd.Parameters.Add(new OleDbParameter("#p2", OleDbType.VarChar));
cmd.Parameters["#p2"].Value = i.Des;
cmd.Parameters.Add(new OleDbParameter("#p3", OleDbType.VarChar));
cmd.Parameters["#p3"].Value = i.Type;
cmd.Parameters.Add(new OleDbParameter("#p4", OleDbType.VarChar));
cmd.Parameters["#p4"].Value = i.Price;
cmd.Parameters.Add(new OleDbParameter("#p5", OleDbType.VarChar));
cmd.Parameters["#p5"].Value = i.Stock;
cmd.Parameters.Add(new OleDbParameter("#p6", OleDbType.VarChar));
cmd.Parameters["#p6"].Value = i.Pic;
The problem is in your update statement. You have single quotation marks surrounding the parameter names. This means that they are interpreted as literal strings and not as the names of the parameter. So your statement is telling the database to update the ItemType with the value '#p3', (which is not a value in your ItemTypes table hence the foreign key violation) and not with the value in the parameter. In fact your parameters are being totally ignored.
Please also remember when using OleDB that the parameter names are ignored. All that matters is that you provide the parameters in the correct order.
Change your sql to this:
string sql = "UPDATE [Items] SET [ItemName]= #p1 , [ItemDes] = #p2 , [ItemType] = #p3 , [Price] = #p4 , [Stock] = #p5, [ItemPic] = #p6 where [ItemCode] = '" +itemCode+ "'";

Writing SQL statement to select from multiple rows

This might be a silly question to ask. I will appreciate any kind of help.
I'm trying to write a query that count the number of rows based on the logic as below:
count no rows where username = #username and friendsname = #friendsname and username = #friendsname and #friendsname = #username where status = 0
consider the table in the diagram below:
The query should return 1 since id '18' and id '20' have reciprocal values. How will this query be written?
I have written the query as follows which doesn't work:
bool flag = false;
StringBuilder query = new StringBuilder();
query.Append("SELECT Count(id) from friends where username=#username AND friend_username=#friend_username AND username = #friend_username AND friend_username = #username");
query.Append(" AND status=0");
using (SqlConnection con = new SqlConnection(Config.ConnectionString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand(query.ToString(), con))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("#username", username));
cmd.Parameters.Add(new SqlParameter("#friend_username", friendusername));
if (Convert.ToInt32(cmd.ExecuteScalar()) > 0)
flag = true;
}
}
return flag;
If I'm not mistaken you're trying to count rows given a specific #username and #friendusername that have reciprocal values based on your conditions.
Below query should help, though - I have not tested it in action!
SELECT COUNT(*) as reciprocal_values_no
FROM table_name tbl1
WHERE
username = #username
AND friend_username = #friendusername
AND status = 0
AND EXISTS (
SELECT 1 FROM table_name tbl2 WHERE tbl1.username = tbl2.friend_username AND tbl1.friend_username = tbl2.username )
try this
select username,friend_username,status, count(*)
from table_name
group by username,friend_username,status
having count(*) > 1

Exception from Stored Procedure not caught in .NET using SqlDataAdapter.Fill(DataTable)

I have a Stored Procedure that I am executing from VB.NET. The SP should insert records into a table and return a set to the calling app. The set returned are the records that were inserted.
If the INSERT fails, the exception is caught and re-thrown in the SP, but I never see the exception in my application. The severity level is 14, so I should see it.
Here is the stored procedure:
BEGIN TRY
BEGIN TRANSACTION
-- Declare local variables
DECLARE #DefaultCategoryID AS BIGINT = 1 -- 1 = 'Default Category' (which means no category)
DECLARE #DefaultWeight AS DECIMAL(18,6) = 0
DECLARE #InsertionDate AS DATETIME2(7) = GETDATE()
DECLARE #SendToWebsite AS BIT = 0 -- 0 = 'NO'
DECLARE #MagentoPartTypeID AS BIGINT = 1 -- For now, this is the only part type we are importing from COPICS ('simple' part type)
DECLARE #NotUploaded_PartStatusID AS TINYINT = 0 -- 0 = 'Not Uploaded'
DECLARE #Enabled_PartStatusID AS TINYINT = 1 -- 1 = 'Enabled'
DECLARE #Disabled_PartStatusID AS TINYINT = 2 -- 2 = 'Disabled'
-- Get the part numbers that will be inserted (this set will be returned to calling procedure).
SELECT c.PartNumber
FROM
COPICSPartFile c
LEFT JOIN Part p on c.PartNumber = p.PartNumber
WHERE
p.PartNumber IS NULL
-- Insert new records from COPICSPartFile (records that don't exist - by PartNumber - in Part table)
INSERT INTO Part
([PartNumber]
,[ReplacementPartNumber]
,[ShortDescription]
,[ListPrice]
,[PartStatusTypeID]
,[Weight]
,[CategoryID]
,[DateInserted]
,[SendToWebsite]
,[FileName]
,[MagentoPartTypeID]
,[PrintNumber])
SELECT
c.PartNumber
,c.ReplacementPartNumber
,c.ShortDescription
,c.ListPrice
,CASE WHEN c.PartStatusTypeID = #Enabled_PartStatusID THEN #NotUploaded_PartStatusID ELSE #Disabled_PartStatusID END
,#DefaultWeight
,#DefaultCategoryID
,#InsertionDate
,#SendToWebsite
,#FileName
,#MagentoPartTypeID
,c.PrintNumber
FROM
COPICSPartFile c
LEFT JOIN Part p on c.PartNumber = p.PartNumber
WHERE
p.PartNumber IS NULL
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
THROW;
END CATCH
And here is the .net code:
Try
'Create command
Dim command As New SqlCommand
command.CommandType = CommandType.StoredProcedure
conn = New SqlConnection(m_ConnectionString)
command.Connection = conn
command.CommandText = "trxInsertPartFromCOPICSPartFile"
With command.Parameters
.AddWithValue("#FileName", fileName)
End With
Dim da As New SqlDataAdapter(command)
Dim dt As New DataTable
da.Fill(dt)
If dt.Rows.Count > 0 Then
Return dt
Else
Return Nothing
End If
Catch ex As SqlException
Dim myMessage As String = ex.Message
Finally
If conn.State <> ConnectionState.Closed Then
conn.Close()
End If
End Try
As I was trying to figure out why the exception (duplicate key) wasn't being caught in my application, I tried commenting out the SELECT statement in the SP just before the INSERT and voila. The exception from the INSERT is caught in the application.
Can someone explain to me why the SELECT statement causes this? I know I can break out the SELECT into another SP, but I'd like to keep it all one atomic transaction if possible. Is this expected behavior? Is there a way around it?
Thanks.
The exception is being swallowed by the Fill method. Instead of using that method, create a SqlDataReader, do a command.ExecuteReader(), and then use the reader to populate the DataTable via Load(). This way the error should occur in the ExecuteReader() method and should be catchable. And then you shouldn't need the SqlDataAdapter.
Try
'Create command
Dim command As New SqlCommand
command.CommandType = CommandType.StoredProcedure
conn = New SqlConnection(m_ConnectionString)
command.Connection = conn
command.CommandText = "trxInsertPartFromCOPICSPartFile"
With command.Parameters
.AddWithValue("#FileName", fileName)
End With
Dim dt As New DataTable
conn.Open()
Dim reader As SqlDataReader = command.ExecuteReader()
dt.Load(reader)
If dt.Rows.Count > 0 Then
Return dt
Else
Return Nothing
End If
Catch ex As SqlException
Dim myMessage As String = ex.Message
Finally
If conn.State <> ConnectionState.Closed Then
conn.Close()
End If
End Try
Also, you might be better off on several levels if you combine the SELECT and the INSERT into a single statement. You can do this via the OUTPUT clause, as follows:
INSERT INTO Part
([PartNumber]
,[ReplacementPartNumber]
,[ShortDescription]
,[ListPrice]
,[PartStatusTypeID]
,[Weight]
,[CategoryID]
,[DateInserted]
,[SendToWebsite]
,[FileName]
,[MagentoPartTypeID]
,[PrintNumber])
OUTPUT INSERTED.[PartNumber] -- return the inserted values to the app code
SELECT
c.PartNumber
,c.ReplacementPartNumber
,c.ShortDescription
,c.ListPrice
,CASE WHEN c.PartStatusTypeID = #Enabled_PartStatusID
THEN #NotUploaded_PartStatusID
ELSE #Disabled_PartStatusID END
,#DefaultWeight
,#DefaultCategoryID
,#InsertionDate
,#SendToWebsite
,#FileName
,#MagentoPartTypeID
,c.PrintNumber
FROM
COPICSPartFile c
LEFT JOIN Part p on c.PartNumber = p.PartNumber
WHERE
p.PartNumber IS NULL

SQLException was unhandled, Dataset -Table Adapter

I have the following stored procedure and I'm calling it from my Windows Forms application DataSet like this:
Me.TransactionTableAdapter.spPaymentApply(130, iAmount, Now)
Although I provide the CustomerID, (and stepping in the code to see if it's actually there - and it is) I get the following error during execution:
Procedure or function 'PaymentApply' expects parameter '#CustomerID', which was not supplied.
Here is my SP:
USE [dbPB]
GO
/****** Object: StoredProcedure [dbo].[PaymentApply] Script Date: 05/30/2013 18:34:01 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[PaymentApply]
#CustomerID int,
#Amount int,
#AsOfDate datetime
AS
WITH Totals AS (
SELECT
T.*,
RunningTotal =
Coalesce (
(SELECT Sum(S.Buyin - Coalesce(S.CreditPaid, 0))
FROM [Transaction] S
WHERE
T.CustomerID = S.CustomerID
AND S.Type = 'Credit'
AND S.Buyin > Coalesce(T.CreditPaid, 0)
AND (
T.Starttime > S.Starttime
OR (
T.Starttime = S.Starttime
AND T.TransactionID > S.TransactionID
)
)
),
0)
FROM
[Transaction] T
WHERE
CustomerID = #CustomerID
AND T.Type = 'Credit'
AND T.Buyin > Coalesce(T.CreditPaid, 0)
)
UPDATE T
SET
T.EndTime = P.EndTime,
T.CreditPaid = Coalesce(T.CreditPaid, 0) + P.CreditPaid
FROM
Totals T
CROSS APPLY (
SELECT TOP 1
V.*
FROM
(VALUES
(T.Buyin - Coalesce(T.CreditPaid, 0), #AsOfDate),
(#Amount - RunningTotal, NULL)
) V (CreditPaid, EndTime)
ORDER BY
V.CreditPaid,
V.EndTime DESC
) P
WHERE
T.RunningTotal <= #Amount
AND #Amount > 0;
;
VB Code:
Private Sub btnTransProcess_Click(sender As Object, e As EventArgs) Handles btnTransProcess.Click
Dim iAmount As Integer
Dim drv As DataRowView = CType(Me.cboCustomerName.SelectedItem, DataRowView)
Dim SelCustId As Integer
SelCustId = drv.Item("CustomerID")
Try
iAmount = CType(txtCreditPayment.Text, Integer)
Catch ex As Exception
MessageBox.Show("Enter a valid Credit Payment Amount!", "Invalid Amount", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Try
MsgBox(SelCustId)
Me.TransactionTableAdapter.spPaymentApply(130, iAmount, Now)
'
'Dim command As New SqlCommand(queryString, connection)
'command.Parameters.AddWithValue("#CustomerID", 123)
End Sub
What happened ?
You didn't provide the parameter.
But.. I double-checked...
Maybe you're not calling it the right way ?
Have you tried something like this :
Dim queryString As String = "exec PaymentApply"
Using connection As New SqlConnection(ConnStrg)
connection.Open()
Dim command As New SqlCommand(queryString, connection)
command.Parameters.AddWithValue("#CustomerID", 123)
// ... same for other non-nullable parameters
Dim reader As SqlDataReader = command.ExecuteReader()
End Using
End Try
Why should I do this ?
When you call your Stored Procedure from you code, you don't provide the #CustomerID int parameter.
Since the parameter is not nullable it expects a value and will not go any further until you give it one.
If you want it to be nullable you can set a default value to it. This way he will take this value if you don't provide a new one. Exemple :
From your code, you pass a parameter like this :
someCommand.Parameters.AddWithValue("#CustomerID", 123)
If you want your parameter to be nullable, do something like this in SQL
#CustomerID int = 123
It sounds like you're using a Table Adapter instead of a Command Object.
see: Table Adapter
and TableAdapter Query Configuration Wizard
Your call to Me.TransactionTableAdapter.spPaymentApply(130, iAmount, Now) looks like it should provide 130 as the CustomerID- but if the code does not compile/work properly, perhaps you should use the configuration wizard.
Or, consider the use of a command object instead. The use of both is outlined here:
How to: Create and Execute an SQL Statement that Returns No Value

SQL: Update does not affect any row

I want to update a dataset in a DB2/AS400 table.
The problem is if I there is string parameter in the parameters list the command does not find a row to update.
For example: If I run the command only with the company number the command will succeed. If I run the command with the company number and facility number the command fails.
Does anyone have any idea?
IDbConnection cn = Tools.GetCnApp();
try
{
StringBuilder sql = new StringBuilder();
sql.AppendLine("UPDATE " + Tools.GetSchemeApp() + "/ChangeReasonAssignments");
sql.AppendLine(" SET Confirmed = #CONF, Confirmed_By = #CONFBY, Confirmed_At = #CONFAT");
sql.AppendLine(" WHERE Company = #CONO AND Facility = #FACI AND Department = #DEPT");
sql.AppendLine(" AND Production_Group = #PRGR AND Manufacturing_Order = #ORDR AND Order_Operation = #OPER");
sql.AppendLine(" AND Confirmed = 0");
IDbCommand cmd = cn.CreateCommand();
cmd.SetParameter("#CONO", this.CompanyNumber);
cmd.SetParameter("#FACI", this.FacilityNumber);
cmd.SetParameter("#DEPT", this.ProductionGroup.Department.Name);
cmd.SetParameter("#PRGR", this.ProductionGroup.Name);
cmd.SetParameter("#ORDR", this.ManufacturingNumber);
cmd.SetParameter("#OPER", this.OperationNumber);
cmd.SetParameter("#CONFBY", Base.User);
cmd.SetParameter("#CONFAT", DateTime.Now.ToString());
cmd.SetParameter("#CONF", 1);
cmd.CommandText = sql.ToString();
if (cmd.ExecuteNonQuery() > 0)
{
}
EDIT
The datatypes in database are:
Company: INTEGER
Facility: VARCHAR
Dpartment: VARCHAR
Production_Group: VARCHAR
Manufacturing_Order:INTEGER
Order_Operation: INTEGER
The datatypes in .NET are:
CompanyNumber: int
FacilityNumber: String
Departmentname: String
ProductionGroup: String
Manufacturingorder: int
OrderOperation: int
sql.ToString() results:
UPDATE TSAEDBDEV/ChangeReasonAssignments SET Confirmed = #CONF, Confirmed_By = #CONFBY, Confirmed_At = #CONFAT WHERE Company = #CONO AND Facility = #FACI AND Confirmed = 0
Try to set the string values into ': cmd.SetParameter("#DEPT", "'" + this.ProductionGroup.Department.Name + "'");