32

I am trying to get the content a table with a dynamic SQL stored procedure called from the database context object (using Entity Framework 6.1.1), in order to populate a GridView control. I fail to retrieve the data.

Here's the stored procedure. It is for a student demonstration about SQL injection in stored procedures, so I KNOW this is inject-able and it's fine.

ALTER PROCEDURE dbo.SearchProducts
  @SearchTerm VARCHAR(max)
AS
BEGIN
  DECLARE @query VARCHAR(max)
  SET @query = 'SELECT * FROM dbo.Products WHERE Name LIKE ''%' + @SearchTerm + '%'''
  EXEC(@query)
END

The C# code behind I then use to execute the stored procedure is :

var db = new MyEntities();
var TEST_SEARCH_TERM = "product";
var result = db.SearchProducts(TEST_SEARCH_TERM);

MyGridView.DataSource = result;
MyGridView.DataBind();

When executed, in the Database Explorer in Visual Studio, the stored procedure works fine. But when executed in the running ASP.NET app, I get an exception in the DataBind() method because result returns -1 instead of an IEnumerable DataSet containing the objects resulting from the stored procedure's SELECT.

How can I retrieve the data and populate my GridView?

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
mak
  • 1,384
  • 1
  • 13
  • 21
  • In your edmx, go to Function Imports --> SearchProducts, and double click it. What is the return type set to? – Vahlkron Aug 21 '15 at 13:02
  • The return type is not set. It's (None). – mak Aug 21 '15 at 13:09
  • Sounds like it needs to be set to Complex. The only thing I might suggest, as I haven't had EF give me issues when I do this is, change your * to explicitly select columns you want in the SP. Maybe EF looks at that to determine your return type. Then update your EDMX so the changes are reflected in EF. – Vahlkron Aug 21 '15 at 13:10
  • Note, EF can be picky. It might be easiest to drop your stored procedure from the EDMX and re-add it completely. I've also had issues on updates not updating everything. Just in case you run into another issue. – Vahlkron Aug 21 '15 at 13:13
  • I'm trying, seems like EF is able to create a complex type by fetching the table structure and infering the columns names. – mak Aug 21 '15 at 14:31

4 Answers4

30

Use the following steps to solve this issue:

  1. 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.
  2. In the Add Function Import dialog, enter the name you want your stored procedure to be referred to in your model for example Search_Products, choose your procedure from the drop down list, and choose the return value of the procedure to be Entities and choose Products from the drop down list.
  3. Then in the code behind:

    var db = new MyEntities();
    var TEST_SEARCH_TERM = "product";
    var result = db.Search_Products(TEST_SEARCH_TERM);//Search_Products is the name that you specified in Function Import dialog
    
    MyGridView.DataSource = result;
    MyGridView.DataBind();
    

The reason that you get -1 for result is that Entity Framework cannot support Stored Procedure Return values out of the box. 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.

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
  • 4
    Sweet mother of all code languages. I HAVE NO freaking idea why it works now. I hope this stays stable. Thanks x1000 dude. +100 reputation well deserved. – mak Sep 02 '15 at 17:45
4

I have come across this before with stored procedures using dynamic SQL. I have had success using complex types if I add the line 'SET FMTONLY OFF;' (see https://msdn.microsoft.com/en-us/library/ms173839.aspx) to the top of my stored procedure before it is added to the EF model. Once you have your model setup with your complex type, be sure to remove this line.

Example:

ALTER PROCEDURE dbo.SearchProducts
  @SearchTerm VARCHAR(max)
AS
BEGIN
  SET FMTONLY OFF;
  DECLARE @query VARCHAR(max)
  SET @query = 'SELECT * FROM dbo.Products WHERE Name LIKE ''%' + @SearchTerm + '%'''
  EXEC(@query)
END
Sculper
  • 756
  • 2
  • 12
  • 24
gotmilk13531
  • 234
  • 1
  • 6
  • 1
    Yeah tried that, did not help me. But I kind of found it interesting because it made me understand the inner workings of EF and how it gets the metadata to build the result set. – mak Sep 11 '15 at 15:13
0

Verify that your EDMX has a return type: Go to Function Imports --> SearchProducts, and double click it.

In order to utilize a Complex return type, Entity Framework will require that you explicitly define column names in your stored procedure instead of using *.

Once your stored procedure is modified to define the column names, you can update your model in the project. (Note, performing a complete drop of the SP, and then adding it back to your edmx may be the best route.)

EDIT

Maybe you can modify your SP like the following:

ALTER PROCEDURE dbo.SearchProducts
  @SearchTerm VARCHAR(max)
AS
BEGIN
  SELECT * FROM dbo.Products WHERE Name LIKE '%' + @SearchTerm + '%'
END
Vahlkron
  • 464
  • 3
  • 15
  • When trying to add a complex type to this stored procedure in the model, model explorer does not let you add it because "the selected stored procedure does not return any column" – mak Aug 21 '15 at 15:44
  • Can you modify it like I have above, or do you have to have @query?....with the exception that you should declare your columns specifically. – Vahlkron Aug 21 '15 at 15:49
  • So... Got it working by defining the return type as an Entity of type "Product". Now what I want is to have the return type to be a complex type, not an entity. Imma try what you suggested. Anyway, your solution helped, I'll accept after my last attempts. – mak Aug 21 '15 at 16:10
  • I'm back on this once again. I have tried your suggestion. Does not work. – mak Sep 02 '15 at 14:51
  • I have narrowed down the problem to the LIKE part of the statement. If I remove the WHERE condition altogether, I have EF generating a complex type automatically on model update. If I let the WHERE condition but replace the @SearchTerm by a constant string, it's the same, EF generates the complex type and it's all good. When I try to use the parameter, it fails... So I guess Dynamic stored procedures in EF are just not possible ? I tried the SETFMT ON trick... and still no. – mak Sep 02 '15 at 14:54
0

You seem to have sorted your problem out, there is official documentation from Microsoft available at the links below:

How to import a stored procedure into your entity data model: https://msdn.microsoft.com/en-us/library/vstudio/bb896231(v=vs.100).aspx

Complex types in the EF designer: https://msdn.microsoft.com/en-gb/data/jj680147.aspx

Make sure you are working with the latest version of .net and you keep your model up to date when you make changes to your database.