Entity framework stored procedure issue - entity-framework

I have following stored procedure defined:
USE [BcmMetrice]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ActivityAdd_proc] #Name nvarchar(max),#Description nvarchar(max) =null ,#Users nvarchar(max),#Object_id nvarchar (15) =null, #Source nvarchar(10) =null, #TemplateId bigint =null, #UserID bigint =null
AS
DECLARE activityUsers_cursor CURSOR FOR
select s from dbo.SplitString(#Users, ';')
DECLARE
#new_ActivityId bigint,
#new_CommentId bigint,
#activityUser_l bigint
BEGIN TRY
INSERT INTO [BcmMetrice].[dbo].[Activity]
([Name]
,[Description]
,[Type]
,[Created])
VALUES
(#Name
,#Description
,ISNULL(#TemplateId,0)
,GETDATE())
SET #new_ActivityId = (SELECT SCOPE_IDENTITY())
INSERT INTO [BcmMetrice].[dbo].[Comment] ([UserID],[CommentText],[Timestamp])
VALUES (ISNULL(#UserID,151),'Activity has been created',GETDATE())
SET #new_CommentId = (SELECT SCOPE_IDENTITY())
INSERT INTO [BcmMetrice].[dbo].[ActivityComment] ([ActivityID],[CommentID])
VALUES (#new_ActivityId, #new_CommentId)
INSERT INTO [BcmMetrice].[dbo].[Log]([Timestamp],[Type],[Data],[StackTrace]) VALUES (GETDATE(),'SQL.ActivityAdd_proc','users='+ISNULL(CAST(#Users as varchar(max)),'empty'),null)
OPEN activityUsers_cursor
FETCH NEXT FROM activityUsers_cursor INTO #activityUser_l
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO [BcmMetrice].[dbo].[Log]([Timestamp],[Type],[Data],[StackTrace]) VALUES (GETDATE(),'SQL.ActivityAdd_proc','Inserting users='+ISNULL(CAST(#activityUser_l as varchar(max)),'empty'),null)
INSERT INTO [BcmMetrice].[dbo].[ActivityUser]
([ActivityId]
,[UserId]
,[Role])
VALUES
(#new_ActivityId
,#activityUser_l
,1)
FETCH NEXT FROM activityUsers_cursor INTO #activityUser_l
END
CLOSE activityUsers_cursor
DEALLOCATE activityUsers_cursor
END TRY
BEGIN CATCH
PRINT 'ERROR'
INSERT INTO [BcmMetrice].[dbo].[Log]([Timestamp],[Type],[Data],[StackTrace]) VALUES (GETDATE(),'SQL.ActivityAdd_proc','ERROR CATCHED!'+ERROR_MESSAGE(),null)
END CATCH
select #new_ActivityId
The thing I would like to do is to return from the procedure the id of a newly added activity. That is why at the very and I use line:
select #new_ActivityId
When testing this procedure in SQL Management Studio everything seems to be working fine. Problem starts when I try to use this procedure in my .NET project. I updated my edmx model form database, but when I execute this procedure the return value is invalid.
Procedure execution looks like this:
int ret = dc.Db.ActivityAdd_proc(name, description, users, object_id, source, templateId, userId);
Does anyone have an idea what I might be doing wrong?

I found solution to my problem. When you try to return data from stored procedure via select statement you must create Function Import in model browser of edmx. In a wizard you choose a type of returned collection (in my case it was scalar of type int64).

Related

How to retrieve the input parameter values of a stored procedure

I want to create a auditing procedure which will be called in the catch block of all the procedure in my Database.
I wanted to store the list of all the input parameters and its values in this auditing DB.
Please suggest me, how to achieve this in SQL Server
I am not aware of programatically retrieving the list of parameters and their values for a stored proc(Possibly would involve n number of system tables and things like that). Without going into that level of complexity AND if altering the current procedures is a possibility, you could do something on the lines of below.
ALTER the existing stored procs to add a small functionality wherein you populate a table variable with
the parameters in a set string format('#paramname = paramvalue') and their values in the current proc
and then fire the Auditing proc if the control reaches the CATCH block.
--Add this code bit on top of the proc from where you want the Audit Proc to be fired
--Declare and insert into a table variable
Declare #ParamValues TABLE (params varchar(400))
insert into #ParamValues
select '#id = '+ #id UNION
select '#name = '+ #name UNION
select '#date = '+ #date
GO
...
....
END TRY
begin catch --Auditing proc code below
exec AuditDB.dbo.AuditProc #ParamValues,
OBJECT_NAME(##PROCID) --this returns the name of current proc
end catch
-------
-------Create the requisite SQL objects
-------
CREATE TABLE AuditDB.dbo.AuditTable
(
AuditMessage varchar(400),
ProcName varchar(200),
DateTimeStamp DateTime
);
GO
CREATE TYPE AuditDB.dbo.ParamValuesType AS TABLE
(
params varchar(400)
);
GO
CREATE PROCEDURE AuditDB.dbo.AuditProc
#ParamValues dbo.ParamValuesType READONLY
,#ProcName varchar(200)
AS
BEGIN --Add whaterver lines of code required, this is just a basic version.
INSERT INTO AuditDB.dbo.AuditTable
SELECT params, #ProcName, cast(getdate() as datetime) FROM #ParamValues
END;

T-sql: Conversion failed when converting the varchar value '61B08729-BB4F-426C-B20B-697F40F458C5' to data type int

I am calling one stored procedure inside another and for some reason SQL Server doesn't like the parameter I am supplying it. Its probably something simple but I am not sure why it doesn't like it.
Stored procedure 1
USE [UserManagerTest]
GO
/****** Object: StoredProcedure [dbo].[sp_UserManager_Log_User_Off] Script Date: 11/19/2012 11:33:53 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Nick Gowdy
-- Create date: 13-11-2012
-- Description: Used by model is UserManager to filter data returned to code
-- =============================================
ALTER PROCEDURE [dbo].[sp_UserManager_Log_User_Off]
#userid UNIQUEIDENTIFIER
AS
BEGIN
-- Get SessionID from UserID
DECLARE #sessionid VARCHAR(60)
DECLARE #userid uniqueidentifier
select #userid = '61B08729-BB4F-426C-B20B-697F40F458C5'
EXEC #sessionid = aspnet_Membership_Custom_GetUserSessionsByUserId #userid
select #sessionid as sessionid
-- Delete user session based on sessionid and userid
EXEC aspnet_Membership_Custom_DeleteUserSession #sessionid, #userid
END
Stored procedure 2
USE [UserManagerTest]
GO
/****** Object: StoredProcedure [dbo].[aspnet_Membership_Custom_GetUserSessionsByUserId] Script Date: 11/19/2012 12:16:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROCEDURE [dbo].[aspnet_Membership_Custom_GetUserSessionsByUserId]
#UserId uniqueidentifier
AS
BEGIN
declare #SessionId varchar(60)
select #SessionId = ( SELECT
[UserId]
FROM
[dbo].[aspnet_Custom_UserSessionActivity]
WHERE
[UserId] = #UserId)
--select #SessionId
RETURN #SessionId
end
Error is this when I execute sp_usermanager_log_user_off
Msg 245, Level 16, State 1, Procedure aspnet_Membership_Custom_GetUserSessionsByUserId, Line 17
Conversion failed when converting the varchar value '61B08729-BB4F-426C-B20B-697F40F458C5' to data type int.
Any ideas? Thanks!
My best guess is that you defined a PROCEDURE when you wanted in fact a FUNCTION.
Stored procedure returns an int, which is the error code. You are trying to return something else (a uniqueidentifier, that is) and it's not working.
You can also modify your procedure to supply OUTPUT parameters.
MSDN Documentation ( http://msdn.microsoft.com/en-us/library/ms187926.aspx ) :
Return a status value to a calling procedure or batch to indicate
success or failure (and the reason for failure).
Use long or float - that string is likely too large to be converted to an integer value

Incorrect Stored Procedure Syntax

I am using the below stored procedure to upload files into a db where each file has a correspondence table but there are times when the table not exist in that case i want to add the file name into a table called NewTables.I can not get the stored proc syntax working can someone help me.I believe the mistake is in the first part where i check if the table exist
ALTER proc [dbo].[UploadCSVFiles]
#FilePath varchar(100) ,
#FileName varchar(100),
#TableName varchar(250)
AS
BEGIN
DECLARE #SqlStmt nvarchar(max)
DECLARE #ErrorCode int
SET #SqlStmt='Truncate table dbo.[' + #TableName +']'
EXEC(#SqlStmt);
set #SqlStmt =N'
IF not EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].['+#TableName +N']'') AND type in (N''U''))
BEGIN
INSERT INTO dbo.NewTables ('+#TableName+N','+#FileName+N') Values('+#TableName+N','+#FileName+N')
END
ELSE
BEGIN
INSERT INTO '+#TableName+N'
select *
from openrowset(''MSDASQL''
,''Driver={Microsoft Access Text Driver (*.txt, *.csv)};
DefaultDir='+#FilePath+N'''
,''select * from "'+#FileName+N'"'')
END
'
EXEC(#SqlStmt);
Thanks
Rao
Thanks fpop and Christine, I have made the suggestions you made but still I get an error
Msg 4701, Level 16, State 1, Line 1
Cannot find the object "Customer" because it does not exist or you do not have permissions.
it seems the If statement does not insert the new table
here is the final version
USE [MyDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[UploadFiles_2]
#FilePath varchar(100) ,
#FileName varchar(100),
#TableName varchar(250)
AS
BEGIN
DECLARE #SqlStmt nvarchar(max)
DECLARE #ErrorCode int
SET #SqlStmt='Truncate table dbo.[' + #TableName +']'
EXEC sp_executesql #SqlStmt;
set #SqlStmt =N'
IF ( NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].['+#TableName +N']'') AND type in (N''U''))
BEGIN
INSERT INTO dbo.NewTables (TableName,FileName) Values('''+#TableName+N''','''+#FileName+N''')
END
ELSE
BEGIN
INSERT INTO '+#TableName+N'
select *
from openrowset(''MSDASQL''
,''Driver={Microsoft Access Text Driver (*.txt, *.csv)};
DefaultDir='+#FilePath+N'''
,''select * from "'+#FileName+N'"'')
END'
EXEC sp_executesql #SqlStmt;
END
Hint: You can always add PRINT #SQLSTMT to see the code your procedure has generated.
There are two error in the script, both in line:
INSERT INTO dbo.NewTables ('+#TableName+N','+#FileName+N') Values('+#TableName+N','+#FileName+N')
First error: NewTables table must have 2 columns to keep table name and file name. Let's call them COL_TBL, COL_FILE
Second error: You have to add quotes in Values part of statement
Here is how it should look like:
INSERT INTO dbo.NewTables (COL_TBL, COL_FILE) Values('''+#TableName+N''','''+#FileName+N''')
btw, You didn't post code entirely, there is an END at the end missing. Please, next time copy the whole code so others can reproduce the error.
EDIT: Please consider following: using sp_executesql instead of EXEC, to avoid sql injection bugs do not concatenate parameters into dynamic sql and finally check if table exists before truncating it
Try this
IF (NOT EXISTS (SELECT * FROM sys.objects WHERE [type] LIKE 'U' AND name LIKE 'mytable'))
SELECT 'not found';
ELSE
SELECT 'found';

Union select statements within the while loop T-SQL

I'm trying to use cursors to dynamically produce a result set. following is the code
DECLARE # MilestoneName VARCHAR(100),
#MilestoneSts VARCHAR(100),
#ProjectPre VARCHAR(10),
#ProjectID VARCHAR(10),
#Center VARCHAR(20),
#CenterPre VARCHAR(20),
#Source VARCHAR(20),
#Actual INT;
SET #MilestoneName = null;
SET #MilestoneSts = null;
SET #ProjectPre = null;
SET #CenterPre = null;
DECLARE s_cursor CURSOR FOR
SELECT ProjectID, Center, Source, Actual
FROM #MILESTONE
OPEN s_cursor
FETCH NEXT FROM s_cursor INTO #ProjectID, #Center, #Source, #Actual
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT ##FETCH_STATUS sts, #ProjectID PID, #Center Center, #Source Source, #Actual Actual
FETCH NEXT FROM s_cursor INTO #ProjectID, #Center, #Source, #Actual
END
CLOSE s_cursor
DEALLOCATE s_cursor
However using that I'm able to produce 79 results of single rows but I want to union all those rows into one result.. any possible solution will be highly appreciated..
just checking, why are you using a cursor for this?
This sproc could be replaced by just saying
SELECT ProjectID, Center, Source, Actual
FROM #MILESTONE
But maybe I'm missing somehting here?
If there's logic you left out in your code look at this post: Multi-statement Table Valued Function vs Inline Table Valued Function
GJ

Call stored proc from after insert trigger

Perhaps a stupid question!
If I call a stored proc from an After Insert trigger (T-SQL) - then how do I get the values of the "just inserted" data?
e.g.
CREATE TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
EXEC createAuditSproc 'I NEED VALUES HERE!'
I don't have any identity columns to worry about - I just want to use some of the "just inserted" values to pass into my sproc.
Edit: For clarification - I need this to call a sproc and not do a direct insert to the table, since the sproc does more than one thing. I'm working with some legacy tables I can't currently amend to do things 'properly' (time/resource/legacy code), so I have to work with what I have :(
You get to the newly 'changed' data by using the INSERTED and DELETED pseudo-tables:
CREATE TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
INSERT INTO myTableAudit(ID, Name)
SELECT i.ID, i.Name
FROM inserted i;
END
Given the example tables
create table myTable
(
ID INT identity(1,1),
Name varchar(10)
)
GO
create table myTableAudit
(
ID INT,
Name varchar(10),
TimeChanged datetime default CURRENT_TIMESTAMP
)
GO
Edit : Apologies, I didn't address the bit about calling a Stored Proc. As per marc_s's comment, note that inserted / deleted can contain multiple rows, which complicates matters with a SPROC. Personally, I would leave the trigger inserting directly into the audit table without the encapsulation of a SPROC. However, if you have SQL 2008, you can use table valued parameters, like so:
CREATE TYPE MyTableType AS TABLE
(
ID INT,
Name varchar(10)
);
GO
CREATE PROC dbo.MyAuditProc #MyTableTypeTVP MyTableType READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO myTableAudit(ID, Name)
SELECT mtt.ID, mtt.Name
FROM #MyTableTypeTVP mtt;
END
GO
And then your trigger would be altered as like so:
ALTER TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MyTableTypeTVP AS MyTableType;
INSERT INTO #MyTableTypeTVP(ID, Name)
SELECT i.ID, i.Name
FROM inserted i;
EXEC dbo.MyAuditProc #MyTableTypeTVP;
END
you can then test that this works for both a single and multiple inserts
insert into dbo.MyTable values ('single');
insert into dbo.MyTable
select 'double'
union
select 'insert';
However, if you are using SQL 2005 or lower, you would probably need to use a cursor to loop through inserted passing rows to your SPROC, something too horrible to contemplate.
As a side note, if you have SQL 2008, you might look at Change Data Capture
Edit #2 : Since you need to call the proc, and if you are certain that you only insert one row ...
ALTER TRIGGER dbo.MyTrigger
ON dbo.MyTable
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SomeInt INT;
DECLARE #SomeName VARCHAR(10);
SELECT TOP 1 #SomeInt = i.ID, #SomeName = i.Name
FROM INSERTED i;
EXEC dbo.MyAuditProc #SomeInt, #SomeName;
END;