I am trying to create a stored procedure that is getting values from a linked to our Sql Server DB2 server.In the stored procedure I have this query:
DECLARE #CarID nvarchar(10)
DECLARE #TSQL varchar(8000)
SET #CarID = '1111'
SELECT #TSQL = 'SELECT * FROM OPENQUERY(LINKEDSERVER,''SELECT * FROM TestTable WHERE Column LIKE ''''' + #CarID + '%' + ''''''')'
EXEC (#TSQL)
Everithing is working fine but when I add the stored procedure to the Entity model the signature of the procedure is:
GetUsers(string):int
But when I run the procedure returns data rows. How can I modify the procedure to return a data set not an integer?
EF handles a stored procedure somewhat similar as a scalar function. EF doesn't know how many datasets and which columns will be selected in your stored procedure, therefore cannot generate the classes.
Best way to select something on a linked server is with a view.
Simply create the view with the four part name and add it to your EF datamodel. Then EF will be able the generate the class.
CREATE VIEW [dbo].[vTestTable]
AS
Select * from [LINKEDSERVER].[DatabaseName].[Schema].[TestTable]
GO
Then in .NET
var result = db.vTestTable.Where(t=> t.Column.StartsWith(CarId)).ToList();
Related
There is a TABLE Type defined in SQL server:
CREATE TYPE RealtySearchResult AS TABLE
(
realtyId int not null,
OwnerId int not null,
...)
And stored procedure:
CREATE PROCEDURE [dbo].[SearchRealty]
(#fulltext nvarchar(200) null,
#skipRows int,
#pageCount int,
....
)
AS
BEGIN
DECLARE #SQL nvarchar(max)
DECLARE #result RealtySearchResult
CREATE TABLE #TEMP
(
realtyId int not null,
OwnerId int not null,
...
)
set #SQL = N'
INSERT INTO #TEMP
SELECT
realty.Id AS realtyId,
realty.OwnerId,
....join with fulltext catalog.... WHERE....#pageCount .....#skipRows'
-- sp_executesql cannot write to local table variable #result,
-- that is why it reads to temp table and then to #result
exec sp_executesql #SQL, N'#skipRows int, #pageCount int', #skipRows, #pageCount
INSERT INTO #result SELECT * FROM #TEMP
SELECT * FROM #result
END
And then in Visual Studio I update the model from database and a new method (wrapper for store procedure SearchRealty) is generated, but it does not contains generated code for returning complex type.
I would expect that EntityFramework should be able to recognize that the store procedure returns defined table type RealtySearchResult and should generate wrapper for it. I am too lazy to write the complex return type by myself in C# again (I just wrote it in SQL). It is really needed?
Can I just generate wrapper for RealtySearchResult type in EntityFramework somehow?
I use Visual Studio 2017 and EntityFramework 6.
It sounds as duplicate as Stored procedure in Entity Framework database first approach but once I click the button Get Column Information I got message "The selected stored procedure or function returns no columns".
Analysis
Based on link Entity Framework not getting column info on a different schema provided by kirsten I realize that EntityFramework execute stored procedure with mode
SET FMTONLY ON
It means it strips all condition and dynamic SQL. This result in empty temporary table and procedure failing during receiving metadata from EntityFramework.
Solution
To help the designer to get metadata without dynamic SQL. Count with that conditions are removed. Following code does a job:
DECLARE #result RealtySearchResult
IF 0=1
BEGIN
SELECT * FROM #result
RETURN
END
During execution of store procedure by EntityFramework (in order to get metadata), condition 0=1 is removed and empty table of Table type is returned which is enough to get metadata. This code is never trigerred in production because of impossible condition.
CREATE PROC spIsValidUser
#UserName varchar(50),
#Password varchar(50)
AS
IF Exists(SELECT * FROM Users where UserName=#UserName and Password=#Password)
BEGIN
return 0
END
ELSE
BEGIN
return 1
END
GO
I have created this Stored Procedure and tring to call this Stored Procedure using entity framework. Below is code in written in C#.
MyBusEntities db = new MyBusEntities();
int empQuery = db.spIsValidUser("abc", "abc#123");
spIsValidUser Stored Procedure return -1 in all case. Please let me know error.
EDIT - According to given answer, Store procedure is not used return statement because Entity Framework cannot support Stored Procedure Return scalar values out of the box..Let me know how can I send scalar data from Stored Procedure?
Your stored procedure is currently returns a scalar value. Use the following steps to solve this issue:
Change your stored procedure like this (Don't use the keyword return in the stored procedure to return the value, Entity Framework cannot support Stored Procedure Return scalar values out of the box. BUT there is a work around):
ALTER PROC spIsValidUser
#UserName varchar(50),
#Password varchar(50)
AS
SELECT Count(*) FROM Users where UserName= #UserName and Password= #Password
return
You need to Import the stored procedure as a Function. Right-click on the workspace area of your Entity model and choose Add -> Function Import.
In the Add Function Import dialog, enter the name you want your stored procedure to be referred to in your model, choose your procedure from the drop down list, and choose the return value of the procedure to be Scalar.
Finally write you code like this:
MyBusEntities db = new MyBusEntities();
System.Nullable<int> empQuery = db.spIsValidUser("abc", "abc#123").SingleOrDefault().Value;
MessageBox.Show(empQuery.ToString());// show 1 if Exist and 0 if not Exist
Edit: I think support of stored procedure return values depends on version of Entity framework. Also Entity Framework doesn't have rich stored procedure support because its an ORM, not a SQL replacement.
Have you tried:
CREATE PROC spIsValidUser
#UserName varchar(50),
#Password varchar(50)
AS
IF Exists(SELECT * FROM Users where UserName=#UserName and Password=#Password)
BEGIN
SELECT 0
END
ELSE
BEGIN
SELECT 1
END
GO
Have you imported your stored procedures in the EF model correctly? and are you setting correct return type to stored procedures??
There are 4 possible return type that you can set to your procedures
The possible return types are:
none
Scalars
Complex
Entities
you need to set scalars return type.
if you dont know how to set the return type, then here is the full tutorial http://www.binaryintellect.net/articles/30738a7c-5176-4333-aa83-98eab8548da5.aspx
quick example.
CREATE PROCEDURE CustOrderCount
#CustomerID nchar(5)
AS
BEGIN
SELECT COUNT(*) FROM ORDERS
WHERE CUSTOMERID=#CustomerID;
END
NorthwindEntities db = new NorthwindEntities();
var count = db.CustOrderCount("ALFKI");
int ordercount = count.SingleOrDefault().Value;
this will return int order count.
I have a stored procedure that inserts into a table then executes this line
SET #returnVal = SCOPE_IDENTITY();
and after that I've tried both:
SELECT #returnVal
and
return #returnVal
When I execute the stored procedure from Microsoft SQL Server Management Studio, I get the expected result with SELECT #returnVal - the identity column for the inserted data is selected.
However when I add the stored procedure to my ADO.Net Entity Data Model / EntityFramework class / .edmx class and execute the stored procedure in my C# code, I get the value -1 returned without fail.
Is it possible to get the value that I want, the new identity value, returned?
I realize that I could manually bind the stored procedure to the insert action of the table in my model - but this is not an option. There are far too many insert procedures to do this manual work every time I regenerate my model class(es).
Declare a output type of parameter in your procedure definition:
create procedure [dbo].[Procedurename] #returnVal int output
as
SET #returnVal = SCOPE_IDENTITY();
and while calling the stored procedure call it as:
declare #returnVal int
exec Procedurename #returnVal output
print #returnVal
taken from the OPs question
Adding an output parameter worked (answer marked below).
The stored procedure signature looks like this now:
My stored procedure signature now looks like this:
CREATE PROCEDURE SP_MyStoreProc ([Multiple Parameters], #returnVal int output)
The last line of the stored procedure is:
return #returnVal
My C# code looks like this now: (db is an instance of my dbContext class)
System.Data.Objects.ObjectParameter identityParameter =
new System.Data.Objects.ObjectParameter("returnVal", 0);
db.SP_MyStoredProc([Multiple Parameters], identityParameter);
int myNewIdentity = Convert.ToInt32(identityParameter.Value);
context.Database.ExecuteSqlCommand return the command executing result and not the query result.
If you need to get data than use context.Database.SqlQuery.
SET #ReturnVal=SCOPE_IDENTITY() and then use the select.
Example:
How to use DbContext.Database.SqlQuery<TElement>(sql, params) with stored procedure? EF Code First CTP5
If you open the edmx file and right click on the function import in the model browser you can tell entity framework that the stored procedure returns a collection of scalars. Then you can essentially call the sproc with mycontext.mysproc().Single() to get the ID.
I am using Entity Framework with C# to make a Silverlight application. I have written some stored procedures which perform database intensive operations and I need to call them from Entity Framework after passing some parameters. In one of the steps, the users select a list of items for which they would need more details. This list of items (in the form of an array of integer IDs) need to be passed to the stored procedure to retrieve more information about those IDs. How do I pass this parameter to the stored procedure?
You can't pass table-valued parameters to SQL with the Entity Framework.
What you can do is create a delimited string like "1|2|3|4" and create a Split function in SQL that will return a table.
CREATE FUNCTION dbo.Split
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
Then if you need to do something like select all items from a table based on what is in the delimited string passed to your proc:
SELECT * FROM SomeTable WHERE Id IN (SELECT Id FROM dbo.Split(#DelStr, '|'))
If you are using SQL Server, which I assume is the case, you can create use a table valued parameter to do what you wish. Using a table valued parameter prevents you from parsing an input parameter within the stored procedure and removes the threat of a SQL injection attack by eliminating the use of dynamic SQL.
Here is a great blog article that covers how to do what you wish to do.
Using Table-Valued Parameters in SQL Server 2008 and C#
Is this what you were looking for?
I have the following stored procedure
ALTER PROCEDURE [dbo].Test
AS
BEGIN
CREATE TABLE ##table
(
ID1 int,
ID2 int
)
DECLARE #query varchar(MAX);
INSERT INTO ##table VALUES(1, 1);
SELECT * FROM ##table;
END
And I try to use it from C# code. I use LINQ to SQL as an O/RM. When I add the procedure to DataBaseContext it says that it can't figure out the return value of this procedure. How to modify the stored procedure so that I can use it with LINQ to SQL.
Note: I need to have global template table!
for MSSQL use SET FMTONLY OFF; at the begining of the proc. Tells SQL to run the stored proc not to make assumptions, which is the only way I've learned to make LINQ work when using temp tables.
Try identifying the columns in your select.
SELECT ID1, ID2 FROM ##table;