The following SQL code works perfectly in [QTY] database. it deletes all the rows in [Table1], then runs the stored procedure [test] and inserts the result into [Table1].
I want to be able to run this code from an MVC controller. How can I achieve this? Thank you.
USE [QTY]
GO
DECLARE #return_value int
Delete from Table1
INSERT INTO Table1
EXEC #return_value = [dbo].[test]
#Month = N'M4',
#Forecast = '2019-04-30'
SELECT 'Return Value' = #return_value
GO
Try to use FromSql method which enables you to pass in a SQL command to be executed against the database to return instances of the type represented by the DbSet .
// Format string
var author = db.Authors.FromSql("SELECT * From Authors Where AuthorId = {0}", id).FirstOrDefault();
// String interpolation
var author = db.Authors.FromSql($"SELECT * From Authors Where AuthorId = {id}").FirstOrDefault();
The DbContext exposes a Database property which includes a method called ExecuteSqlCommand. This method returns an integer specifying the number of rows affected by the SQL statement passed to it.
using(var context = new SampleContext())
{
var commandText = "INSERT Categories (CategoryName) VALUES (#CategoryName)";
var name = new SqlParameter("#CategoryName", "Test");
context.Database.ExecuteSqlCommand(commandText, name);
}
You could take some time on the tutorial Executing Raw SQL Queries
It is my understanding that there is no elegant way to call a stored procedure in EF6 using table-valued parameters. Can someone verify or discredit my suspicion?
Table-valued type:
CREATE TYPE MyTestType AS TABLE
(
ID INT,
String VARCHAR(30)
);
Stored procedure:
CREATE PROCEDURE MyTestProc
#TestVar MyTestType READONLY
AS
BEGIN
SELECT * FROM #TestVar
END
C# EF call:
var testTable = new DataTable();
testTable.Columns.Add("ID", typeof (int));
testTable.Columns.Add("string", typeof (string));
testTable.Rows.Add(1, "Row1");
var parameter = new SqlParameter("#TestVar", SqlDbType.Structured);
parameter.Value = testTable;
parameter.TypeName = "dbo.MyTestType";
var results = dbContext.Database.SqlQuery<TestObject>("exec dbo.MyTestProc #TestVar", parameter).ToList();
The code above is working, I would just like to see if there is a more elegant way of executing it. I feel like I should be allowed to do something like
var results = dbContext.MyTestProc(testTable).ToList();
Edit
I came across this article which has a slightly cleaner way of handling the data table, but still hoping for a cleaner way to call my stored procedure with the table-valued parameter.
Code.msdn - Stored Procedure with Table-Valued Parameter in EF and ASP.NET MVC
I have a stored procedure in a Microsoft SQL Server database:
USE [ProjectIndexer]
GO
/****** Object: StoredProcedure [files].[add_file] Script Date: 12/12/2014 1:34:20 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [files].[add_file]
#FILENAME varchar(255),
#EXTENSION nvarchar(8),
#PATH_FULL varchar(255),
#RELATIVE_PATH varchar(255),
#JOB varchar(15),
#DATE_MODIFIED datetimeoffset(7),
#SIZE BIGINT,
#INDEX_MODULE INT,
#FILE_TYPE varchar(255),
#DOC_TYPE varchar(255),
#DISCIPLINE varchar(255)
AS
DECLARE #file_id sql_variant
--Insert values for new file
INSERT INTO files.GENERAL
(FILENAME, EXTENSION, PATH_FULL, RELATIVE_PATH, JOB, DATE_MODIFIED, SIZE, INDEX_MODULE, FILE_TYPE, DOC_TYPE, DISCIPLINE)
VALUES(#FILENAME, #EXTENSION, #PATH_FULL, #RELATIVE_PATH, #JOB, #DATE_MODIFIED, #SIZE, #INDEX_MODULE, #FILE_TYPE, #DOC_TYPE, #DISCIPLINE);
--Get the ID of this new file
SELECT #file_id = current_value FROM sys.sequences WHERE name = 'FILE_ID_SEQ';
--Return ID
RETURN CONVERT(bigint, #file_id)
I am trying to run this procedure in a VB application developed in Visual Studio 2012, using table adapters:
Dim myFilesGeneralTableAdapter As New FILES_GeneralTableAdapter
Dim FileID As Int32
FileID = myFilesGeneralTableAdapter.AddFile(FileName, fileExtension, foundFile, fileRelativePath, JobNumber, fileDateModified, fileSize, Nothing, Nothing, Nothing, Nothing)
For some reason, the function isn't returning the value to the VB variable 'FileID'. I can, however, use the "Preview Data" feature in the dataset designer to insert values for the above parameters in Visual Studio, and in that environment I'm able to get a returned value.
This suggests to me that my syntax in my VB module is wrong. Can anyone tell me what the error is?
Have you considered using System.Data.SqlClient.SqlCommand? You can use it to call your stored procedure, add the parameter values, and execute it in such a way that you retrieve a single value, i.e.
Try
'Create command'
Dim command As New SqlCommand
command.CommandType = CommandType.StoredProcedure
conn = New SqlConnection(myConnString)
command.Connection = conn
command.CommandText = "add_file"
command.Parameters.AddWithValue("#Filename", [Filename])
...
command.Parameters.AddWithValue("#Discipline", Discipline)
command.Connection.Open()
Dim i As Int64 = command.ExecuteScalar()
command.Connection.Close()
'returns record ID'
Return i
Catch ex As Exception
Throw ex
Finally
If conn.State <> ConnectionState.Closed Then
conn.Close()
End If
End Try
Please note that, in this example, "myConnString" is a String with the value of my connection string for the database I'm connecting to.
I took the good advice of transitioning the script to an Entity Framework model. At first, the stored procedure did not return what I wanted (it only returned an integer value of 1), but I found a resource online that instructed me to create a "Function Import" in the EF model. After doing that and properly matching variable types I managed to get the stored procedure to return the right value in Visual Studio. Here's a good resoure:
http://www.devtoolshed.com/using-stored-procedures-entity-framework-scalar-return-values
Outside of converting from TableAdapter to Entity Framework (a good move regardless), you would be much_better off returning such a value as either an OUTPUT parameter or in a result set. A stored procedure return value is really intended to convey a status code of the operation and is hence pretty limited.
Also, by doing the following operation after the INSERT (i.e. as a separate step),
--Get the ID of this new file
SELECT #file_id = current_value FROM sys.sequences WHERE name = 'FILE_ID_SEQ';
you are risking getting an incorrect value if some other process inserts into that table at roughly the same time (i.e. between this particular INSERT and this particular SELECT).
Given both of the above issues, it would be fairly simple, and very reliable, to instead use the OUTPUT clause on the INSERT statement:
--Insert values for new file
INSERT INTO files.GENERAL
(FILENAME, EXTENSION, PATH_FULL, RELATIVE_PATH, JOB, DATE_MODIFIED, SIZE,
INDEX_MODULE, FILE_TYPE, DOC_TYPE, DISCIPLINE)
OUTPUT INSERTED.FILE_ID
VALUES(#FILENAME, #EXTENSION, #PATH_FULL, #RELATIVE_PATH, #JOB, #DATE_MODIFIED,
#SIZE, #INDEX_MODULE, #FILE_TYPE, #DOC_TYPE, #DISCIPLINE);
That will generate a 1 row, 1 column result set. The column will be named FILE_ID or whatever the actual field name is (I guess based on the naming convention used for the other fields and the variable).
Then get rid of the DECLARE #file_id, the SELECT ..., and the RETURN ....
Using Simple.Data, I would like to get the result from an output parameter in a stored procedure. Let's say I have the following SP (disregard the uselessness of it):
CREATE PROCEDURE [dbo].[TestProc]
#InParam int,
#OutParam int OUTPUT
AS
BEGIN
SELECT #OutParam = #InParam * 10
END
When I call it with Simple.Data, I use the following code.
var db = Database.Open();
int outParam;
var result = db.TestProc(42, out outParam);
Console.WriteLine(outParam); // <-- == 0
Console.WriteLine(result.OutputValues["OutParam"]); // <-- == 420
It feels like outParam should contain the value, and not the OutputValues dictionary. So my question is: Is there a nicer way to get the result from OutParam in this particular case?
Unfortunately, out parameters are not supported by the dynamic binding infrastructure used by Simple.Data, as they are not supported in all CLR languages.
I am open to suggestions for better syntax, though.
Well I've been using Model-First with DbSet code generation. And now I what I want to do is to add some stored procedures.
But Code I get look like like:
public virtual ObjectResult<Nullable<int>> CountPostsInThread(Nullable<int> threadID, ObjectParameter postCount)
{
var threadIDParameter = threadID.HasValue ?
new ObjectParameter("threadID", threadID) :
new ObjectParameter("threadID", typeof(int));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Nullable<int>>("CountPostsInThread", threadIDParameter, postCount);
}
Now, how Do I get rid off all those ?
It's something wrong with tt files, or with my stored procedure ?
SP:
ALTER PROCEDURE dbo.sp_CountPostsInThread
(
#threadID int,
#PostCount int = 0 OUTPUT
)
AS
SELECT COUNT(*)
FROM PostSet
WHERE PostSet.ThreadID = #threadID
Nothing is wrong with the template or stored procedure. SP's parameters accept NULL value so because of that EF makes them nullable. The ternary operator is used because if you pass null EF must somehow pass the type of null parameter to correctly setup SqlParameter used internally.