I am to create a stored procedure to create a table to capture form data, this is part of a bigger project to create a Form Generator.
I was wondering if anyone had created a stored procedure that took a stringified JSON object as input and created the the table based on this schema?
I'm still toying with this in my brain as to whether I should be doing this within the sproc (preferable) or writing dynamic sql within a C# Service.
Personally I wouldn't approach this problem by passing the JSON string to a stored procedure. However, if you wish to do it this way you could pass the JSON object directly to the stored procedure and then manipulate the string as below. I have provided the code to manipulate the table name and create a table based upon the example JSON string '{TABLENAME:TABLENAME, Fields: {field1:varchar, field2: int }}'. You would then have to modify this to include fields and datatypes based upon the string.
CREATE PROCEDURE CreateTableFromJSON
(
#JSON VARCHAR(100)
)
AS
DECLARE #TableName VARCHAR(100)
SET #TableName = SUBSTRING(#json, CHARINDEX(':', #json)+1, CHARINDEX(',', #json) -CHARINDEX(':', #json)-1)
DECLARE #SQL VARCHAR(100)
SET #SQL = 'CREATE TABLE ' + #TableName + ' (ID INT)'
EXEC(#SQL)
GO
EXEC CreateTableFromJSON '{TABLENAME:TABLENAME, Fields: {field1:varchar, field2: int }}'
Related
I've got a stored procedure that returns data for a grid control. Given a table name, the grid will display data from that table. The user can sort and filter this data. There is also paging logic for large data sets.
The names of the tables that data is pulled from is not known until runtime, so dynamic SQL was used. This works well, but is vulnerable to SQL injection - the tableName, sortExpression and filterExpression variables are generated clientside and passed through to the server.
Below is a simplified version of the procedure:
create procedure ReadTable (
#tableName as varchar(128),
#sortExpression as varchar(128),
#filterExpression as varchar(512)
)
as
begin
declare #SQLString as nvarchar(max) =
'select * from ' + #tableName +
' where ' + #filterExpression +
' order by ' + #sortExpression
exec Sp_executesql #SQLString
end
I'm struggling to find a way to easily prevent SQL injection in this case. I've found a good answer explaining how to check the #tableName is legitamite (How should I pass a table name into a stored proc?), but the approach won't work for the filtering or sort strings.
One way would be perhaps to do some sanitizing server side before the data is passed through to the database - breaking the expressions down into column names and checking them against the known column names of the table.
Would there be an easier way?
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?
Use the following steps to solve this issue:
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 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.
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.
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
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
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.
I'm trying to map some insert/update stored procedures to a table in EF. But one of my column types (string) in the stored procedure is different to the column in the table (geometry).
I have a Geometry column in the table that I want to populate in the stored procedure by passing it a string value.
Stored procedure:
CREATE PROCEDURE [dbo].[UpdatePLACE]
#globalid uniqueidentifier,
#shapeString varchar(max) = null
AS
BEGIN
SET NOCOUNT ON;
declare #shape as geometry
set #shape = geometry::STGeomFromText(#shapeString, 2193)
UPDATE [dbo].[PLACE]
SET [SHAPE] = #shape
WHERE [globalid] = #globalid
END
So, is it possible to map a string to a geometry type and how?
I am using the following technologies:
MS SQL 2008 R2
Visual Studio 2010
Silverlight project
LINQ to SQL
When dragging a stored procedure into the data model, and the stored procedure returns an OUTPUT parameter, it works fine. However when the stored procedure returns a result set created with dynamic SQL I receive the following error:
"Unknown Return Type, The return type for the following stored procedure could not be detected."
If the stored procedure does not use dynamic SQL, it works fine.
(For example: SELECT column1 from table2)
The stored procedure however uses dynamic SQL to query a specified view for the data. Simplified below for illustration purposes:
CREATE PROCEDURE GetViewData
#ViewName nvarchar(150)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql nvarchar(MAX)
SET #Sql = 'SELECT Column1, Column2, Column3 FROM' + #ViewName
EXEC sp_executesql #Sql
END
Instead of returning the result set directly, I can place the result set into a temp table. This however gives the same error.
According to the article from Ritesh, when placing the result set into a table type variable this should do the trick, however this is not possible in dynamic sql as the scope is only within the executed dynamic sql.
Ritesh's article:
http://riteshkk2000.blogspot.com/2010/08/error-unknown-return-type-return-types.html
Upon further investigation I realized that the meta data received by LINQ to SQL does not contain the necessary information to define the type.
Apparently with SQL 2012 this can be resolved by using "WITH RESULTS SET" to actually define the meta data manually.
I resolved this by creating another stored procedure, calling GetViewData without using dynamic SQL and populating a table type variable:
CREATE PROCEDURE CallGetViewData
#ViewName nvarchar(150)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ViewResultSet TABLE
(
column1 nvarchar(50),
column2 int,
column3 float
)
INSERT INTO #ViewResultSet
EXEC GetViewData #ViewName
SELECT column1, column2, column3 FROM #ViewResultSet
END
Now when I drag stored procedure CallGetViewData into the data model, it detects the return type correctly.
One trick you can try is to manually create a model that represents the shape of the object that the Stored Proc will return. Then using the designer, don't drag the proc into the method pane, but rather drop it on the type you created manually. LINQ to SQL will then use that class as the result type.
If you already have the method defined for the stored proc, you can change the Return Type using the F4 property window to any type that matches the result shape that you've defined in the model.
I have to insert new records in a database every day from a text file ( tab delimited).
I'm trying to make this into a stored procedure with a parameter for the file to read data from.
CREATE PROCEDURE dbo.UpdateTable
#FilePath
BULK INSERT TMP_UPTable
FROM #FilePath
WITH
(
FIRSTROW = 2,
MAXERRORS = 0,
FIELDTERMINATOR = '\t',
ROWTERMINATOR = '\n'
)
RETURN
Then i would call this stored procedure from my code (C#) specifying the file to insert.
This is obviously not working, so how can i do it ?
Just to be clear the problem here is that i can't pass the parameter #FilePath to the FROM clause, or at least i don't know how.
Sorry, I misunderstood.
You need to create the SQL statement dynamically and then execute it:
CREATE procedure dbo.UpdateTable
#FilePath varchar(max)
AS
declare #sql varchar(max)
declare #parameters varchar(100)
set #parameters = 'FIRSTROW = 2, MAXERRORS = 0, FIELDTERMINATOR = ''\\t'', ROWTERMINATOR = ''\\n'' '
SET #SQL = 'BULK INSERT TMP_UPTable FROM ' + #FilePath + #parameters
EXEC (#SQL)
RETURN
Sorry if I am late here, but I would suggest a different approach - open the file in your C# application and convert it to something more SQL-friendly, a DataTable or even XML. In C# you have complete control over how you parse the files. Then write the stored procedure to accept your DataTable or XML. A DataTable is preferable, but cannot be used with Entity Framework.
There is lots of help around of how to do inserts by joining to this sort of input, and SQL Server is optimised for set operations.