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();
I have a stored procedure with couple parameters. My data table type has 2 columns (int, nvarchar).
When I run this stored procedure and pass IEnumerable<SqlDataRecords> with defined type then query results on my machine is 9 times slower than the same stored procedure without passing this parameter.
The stored procedure doesn't touch this param. Only passing.
It looks like something (sql server?) do with data passed as structured (table-valued) value.
Maybe I am missing something. Maybe there is special switch to:
off any kind of validation
anything else?
Type:
CREATE TYPE dbo.MyData AS TABLE
(
[Ver] INT NOT NULL,
[Name] NVARCHAR(225) NOT NULL
)
Stored procedure:
CREATE PROCEDURE [dbo].[SaveData]
(#Id UNIQUEIDENTIFIER, #Data MyData READONLY)
AS
BEGIN
SET NOCOUNT ON;
END
UPDATE 1:
I've changed query. This stored procedure does nothing. Difference is in passing value or null.
UPDATE 2:
Added stored procedure and type definition.
UPDATE 3:
I'm using SQL Server 2014 Express.
UPDATE 4:
5000 iterations with parameter takes 11281ms (443/sec), without table-valued param - 1029ms (4856/sec).
I would advise running SQL Profiler to examine your queries on the database. You can also look into using SSMS Activity Monitor by right clicking on the database, by clicking on 'activity monitor', and may get lucky and see a 'recent expensive query'.
hth
Is it possible to get the column name/types from a stored procedure in an empty DataTable without calling the stored procedure?
This stored procedures also have parameters which I dont want to provide.
Is this possible or do I have to rethink my approach?
In Sql Server 2012 they introduced a function called dm_exec_describe_first_result_set_for_object which does exactly what you want. As long as your procedure only is returning one result set.
SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set_for_object
(
OBJECT_ID('master.sys.sp_who'),
NULL
);
Another option is to use FMTONLY and then call the procedure. Executing this will get you an empty datatable with the correct column names.
In this case you would need to supply the parameters for the stored procedure.
SET FMTONLY ON;
exec sp_who
FMTONLY is deprecated as of Sql Server 2012 so I would avoid it if possible.
I have a stored procedure that contains dynamic select. Something like this:
ALTER PROCEDURE [dbo].[usp_GetTestRecords]
--#p1 int = 0,
--#p2 int = 0
#groupId nvarchar(10) = 0
AS
BEGIN
SET NOCOUNT ON;
DECLARE #query NVARCHAR(max)
SET #query = 'SELECT * FROM CUSTOMERS WHERE Id = ' + #groupId
/* This actually contains a dynamic pivot select statement */
EXECUTE(#query);
END
In SSMS the stored procedure runs fine and shows result set.
In C# using Entity Framework it shows returning an int instead of IEnumerable?
private void LoadTestRecords()
{
TestRecordsDBEntities dataContext = new TestRecordsDBEntities();
string id = ddlGroupId.SelectedValue;
List<TestRecord> list = dataContext.usp_GetTestRecords(id); //This part doesn't work returns int
GridView1.DataSource = list;
}
Generated function for usp_GetTestRecords
public virtual int usp_GetTestRecords(string groupId)
{
var groupIdParameter = groupId != null ?
new ObjectParameter("groupId", groupId) :
new ObjectParameter("groupId", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("usp_GetTestRecords", groupIdParameter);
}
I get this when I have a stored procedure that includes an "exec" call into a temporary table, such as:
insert into #codes (Code, ActionCodes, Description)
exec TreatmentCodes_sps 0
It appears that Entity Framework gets confused as to what should be returned by the procedure. The solution I've come across is to add this at the top of the sproc:
SET FMTONLY OFF
After this, all is well.
I got the same problem, and found solution here
Move to your .edmx
At Model Browser Window/Function Imports find your procedure then double click it
Change the return type to you want
Save .edmx and check the return type again.
It should be what you need now.
Entity Framework can't tell what your stored procedure is returning. I've had success creating a table variable that mirrors the data from your SELECT statement. Just insert into the table variable then do a select from that table variable. EF should pick it up.
See Ladislav Mrnka's answer in this Stack Overflow post
https://stackoverflow.com/a/7131344/4318324
I had the same basic problem.
Adding
SET FMTONLY OFF
To a procedure you are trying to import during the import will address this problem.
It's a good practice to remove the line afterwards unless the purpose of the database is solely to provide schema for EF (Entity Framework).
The main reason for caution is that EF uses this setting to prevent data mutations when trying to obtain metadata.
If you refresh your entity model from a database any procedures with this line in them can potentially update the data in that database just by trying to obtain the schema.
I wanted to add a further note on this so it's not needed to fully scan through the other link.
if you want to try to use FMTONLY here are a couple things to keep in mind.
when FMTONLY is on:
1) only the schema is returned (no) rows.
similar to adding a blanket false statement to your where clause (ie "where 1=0")
2) flow control statements are ignored
Example
set fmtonly on
if 1=1
begin
select 1 a
end
else
begin
select 1 a,2 b
end
while 1=1
select 1 c
The above returns NO rows whatsoever and the metadata for each of the three queries
For this reason some people suggest toggling it off in a way that takes advantage of it's non-observance of flow control
if 1=0
begin
set fmtonly off
end
In fact you could use this to introduce logic that tracks this
set fmtonly off
declare #g varchar(30)
set #g = 'fmtonly was set to off'
if 1=0
begin
set fmtonly off
set #g = 'fmtonly was set to on'
end
select #g
Think VERY CAREFULLY before trying to use this feature as it is both deprecated and potentially makes sql extremely hard to follow
the MAIN concepts that need to be understood are the following
1. EF turns FMTONLY on to prevent MUTATING data from executing stored procedures
when it executes them during a model update.
(from which it follows)
2. setting FMTONLY off in any procedure that EF will attempt to do a schema scan
(potentially ANY and EACHONE) introduces the potential to mutate database
data whenever *anyone* attempts to update their database model.
Entity Framework will automatically return a scalar value if your stored procedure doesn't have a primary key in your result set. Thus, you'd have to include a primary key column in your select statement, or create a temp table with a primary key in order for Entity Framework to return a result set for your stored procedure.
I had the same problem, I changed the name of return fields by 'AS' keyword and addressed my problem. One reason for this problem is naming column names with SQL Server reserved keywords.
The example is fallows:
ALTER PROCEDURE [dbo].[usp_GetProducts]
AS
BEGIN
SET NOCOUNT ON;
SELECT
, p.Id
, p.Title
, p.Description AS 'Description'
FROM dbo.Products AS p
END
Best solution I found is to cheat a little.
In the store procedure, comment everything, put a first line with a select [foo]='', [bar]='' etc...
Now update the model, go to the mapped function, select complex type and click on Get Column Information and then Create Complex Type.
Now comment the fake select and un-comment the real store procedure body.
When you generated your model class for your stored procedure, you chose scalar return result by mistake. you should remove your stored procedure from your entity model, then re-add the stored procedure. In the dialog for the stored procedure, you can choose the return type you are expecting. Do not just edit the generated code.. this may work now, but the generated code can be replaced if you make other changes to your model.
I have pondered this a bit and I think I have a better/simpler answer
If you have a complex stored that gives entity framework some difficultly (for current versions of Entity Framework that are using the FMTONLY tag to aquire schema)
consider doing the folowing at the beginning of your stored procedure.
--where [columnlist] matches the schema you want EF to pick up for your stored procedure
if 1=0
begin
select
[columnlist]
from [table list and joins]
where 1=0
end
if you are okay loading your result set into a table variable
you can do the following to help keep your schema in sync
declare #tablevar as table
(
blah int
,moreblah varchar(20)
)
if 1=0
begin
select * from #tablevar
end
...
-- load data into #tablevar
select * from #tablevar
If you need to do this, then you might be better off just making a partial of the dbcontext and creating the C# function yourself that will use SqlQuery to return the data you need. Advantages over some of the other options is:
Don't have to change anything when the model updates
Won't get overwritten if you do it directly in the generated class (someone above mention this as if it's an option :) )
Don't have to add anything to the proc itself that could have side effects now or later on
Example Code:
public partial class myEntities
{
public List<MyClass> usp_GetTestRecords(int _p1, int _p2, string _groupId)
{
// fill out params
SqlParameter p1 = new SqlParameter("#p1", _p1);
...
obj[] parameters = new object[] { p1, p2, groupId };
// call the proc
return this.Database.SqlQuery<MyClass>(#"EXECUTE usp_GetTestRecords #p1, #p2, #groupId", parameters).ToList();
}
}
Just change to
ALTER PROCEDURE [dbo].[usp_GetTestRecords]
--#p1 int = 0,
--#p2 int = 0
#groupId nvarchar(10) = 0
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM CUSTOMERS WHERE Id = #groupId
END
I know this is an old thread but in case someone has the same problems I'll tell my woes.
As a help to find the issue, run sql profiler when you add your stored proc. Then you can see what entity framework is passing as parameters to generate your resultset. I imagine nearly always it will pass null parameter values. If you are generating sql on the fly by concatenating string values and parameter values and some are null then the sql will break and you wont get a return set.
I haven't needed to generate temp tables or anything just an exec command.
Hope it helps
During import
SET FMTONLY ON
can be used for taking the sp schema.
If you change the sp and want to update the new one, you should delete the old defined function from edmx file (from xml), because although deleting sp from model browser, it is not deleted in edmx. For example;
<FunctionImport Name="GetInvoiceByNumber" ReturnType="Collection(Model.Invoice_Result)">
<Parameter Name="InvoiceNumber" Mode="In" Type="Int32" />
</FunctionImport>
I had the same problem, and when I delete the FuctionImport tag of corresponding sp totally, the model updated right. You can find the tag by searching the function name from visual studio.
You may have luck opening up the model browser, then going to Function Imports, double clicking the stored procedure in question and then manually clicking "Get Column Information" and then clicking "Create New Complex Type". This usually sorts out the problem.
Well I had this issue as well but after hours of online searching none of above methods helped.
Finally I got to know that It will happen if your store procedure is getting some parameters as null and which generate any error in query execution.
Entity Framework will generate method for store procedure by defining the complex entity model. Due to that null value your store procedure will return and int value.
Please check your store procedure either its providing empty result set with null values. It will fix your problem. Hopefully.
I think this is a problem of permissions on the database, I don't know what exactly could be, but, in my job we use Active Directory users to grant applications connect to databases, this accounts are specially created for the applications, each app has its own user account, well, as a developers I have permissions for read, write and other basic things, no alter, and no advanced features, and I have this same problem running Visual Studio with my normal account, then, what I did was to open Visual Studio selecting the option "as a different user" on the context menu, and I put the AD login granted for the application and voila!, now my Stored Procedures are loading with all the fields I was expected, before that, my Stored Procedures was returning as int. I hope this help someone, maybe the VIEW DEFINITION permissions on database account do the trick
If SQL Authentication is in place, verify that the user credential that is being used to connect Entity Framework to the database has the proper rights to read from CUSTOMERS table.
When Entity Framework uses SQL Authentication to map complex objects (i.e stored procedures that SELECTs more than one column), if any of the tables from within such stored procedure don't have set up the Read permission, the mapping will result in returning INT instead of the desired Result set.
I have written the following stored procedure in SQL Server 2008 :
ALTER Procedure [dbo].[usp_TodayNumberOfRegisteration]
(
#TodayShamsiDate nvarchar
)
AS
Select COUNT(csci.Id) as cc1 FROM dbo.Complex_Service_Cart_Items csci INNER JOIN dbo.Complex_Service_Cart csc
ON csci.Id_Complex_Service_Cart=csc.Id
WHERE (csci.Id_Complex_Service='2cca1a67-34f4-4837-bebe-f3ba4c72b98d' or csci.Id_Complex_Service='8430cad2-dbb1-4425-bb8b-a7e158f688c4')
and csc.TFIsPaymentComplete=1
and csc.TFDateBackFromBankp= RTRIM( #TodayShamsiDate)
And I am calling it from C# codebehind via EF4 this way :
string shamsiDate = Date.getShamsiDate();
returnValue = Convert.ToString(db.getTodayNumberOfRegisteration(shamsiDate).First().Value);
where getTodayNumberOfRegisteration is a function I added to my edmx model .
Now here is the issue : when I execute the stored procedure in SQL Server and instead of
and csc.TFDateBackFromBankp= RTRIM( #TodayShamsiDate)
I set something like :
and csc.TFDateBackFromBankp= RTRIM( '1391/12/05')
This stored procedure returns a value of 6
But when I pass the parameter from C# codebehind and I get the return value '0'
Any help would be appreciated.
I normally do it like this: in the Add Function Import dialog, select your stored procedure and define that it returns a Collection Of Scalars: Int32:
Then in your code, call it like this:
int value = db.getTodayNumberOfRegisteration(shamsiDate).First().Value;
This usually works just fine for me.
If you don't define it as returns a collection of: Int32, it seems that the value you're getting back is really the return value from the stored procedure call, e.g. the number of rows that were affected by the stored procedure execution (0 or -1 for a SELECT, since you didn't actually insert, update or delete any rows):
I found the issue :
I had set the parameter this way :
#TodayShamsiDate nvarchar
and I should have specified the length of nvarchar
#TodayShamsiDate nvarchar(10)
I did It and the problem is solved !