Why am I unable to create a trigger using my SqlCommand? - c#

The line cmd.ExecuteNonQuery();
cmd.CommandText
CREATE TRIGGER subscription_trig_0 ON subscription AFTER INSERT AS UPDATE user_data SET msg_count=msg_count+1 FROM user_data
JOIN INSERTED ON user_data.id = INSERTED.recipient;
The exception:
Incorrect syntax near the keyword 'TRIGGER'.
Then using VS 2010, connected to the very same file (a mdf file) I run the query above and I get a success message. WTF!

Options
The 1st line of the actual SQL sent is not CREATE TRIGGER
CommandType is wrong (eg it's trying to add EXEC or some "prepare" commands)
Use SQL profiler to see exactly what you're sending on to the DB engine (you actually have Express edition that is hosting the MDF)

Do you have CommandType set wrong?

I am not sure why this is failing but if I were you I would use SMO for ddl queries. In this case you need Trigger.Create Method.

Related

How can CRUD using wpf form to sql databse?

How to resolve : insert error column name or number of supplied values does not match table definition?
I have attempted to use the same data type used in the SQL database however when I run my program in visual studio C# I couldn't get the desired outcome I want
Try to specify the columns name you want to insert ("insert into yourTable (col1, col2) values (#para1, #para2);")
Also, I have never seem a paraneter being added like that. If the above doesn't work, try using Parameters.AddWithValue().
When dealing with connections, use:
using (var con = /*Connection declaration*/) {
con.Open();
// use connection here
}
This is important because, if you command fail, the connection will not be closed, meaning that soon, you server will be full of dead connections.

Stored procedure executes but does not update data

I have a stored procedure in a SQL Server 2005 database that's accessed by ASP.NET / C# code.
The parameters for the stored procedure are defined in the typical manner:
Try
{
SqlCommand cmd = new SqlCommand("mystoredprocedure",myConnection)
cmd.Parameters.Add(new SqlParameter("#p1"), SqlDbType.Int))
cmd.Parameters["#p1"].Value = myvalue (usually form inputs)
.
.
.
myConnection.Open()
cmd.ExecuteNonQuery()
}
catch (Exception xx)
{
lblError.Text = xx.Message;
}
finally
{
myConnection.Close();
}
The problem is my data never updates, though the stored procedure doesn't throw any errors. I've checked the procedure in SQL Server, and when I call it directly through SQL Server the proc makes my updates.
I'm tearing my hair out on this one since it worked fine for a long time, then stopped working. I've checked the usual culprits (db connection is pointing to the right database, the procedure seems to work fine in SQL Server, and I've commented out the few new parameters I've created)
Any thoughts on what could be causing this? It's strange that the same procedure works in SQL Server but not through my code without throwing any errors. (To be sure, I put a return value in the stored procedure, and the return value indicates I'm not rolling back)
EDIT
Code for the stored procedure:
BEGIN TRANSACTION
--get count
update dbo.myTable set
val1=#val1,
val2=#val2,
.
.
.
WHERE ID=#MyID
SET #Err = ##ERROR
--if error rollback transaction
IF #Err <> 0
BEGIN
ROLLBACK TRANSACTION
GOTO ErrorHandler
END
Select #ReturnCode = 1
COMMIT TRANSACTION
RETURN
ErrorHandler:
--unknown error
Select #ReturnCode = 0
RAISERROR (#Err, 16, 1 ) WITH LOG
RETURN -100
EDIT
When I parse cmd.ExecuteNonQuery, I get -1 as a result. Still trying to figure out why the C# code is doing this but not throwing any errors. Shouldn't ExecuteNonQuery return the number of rows affected by the stored procedure?
EDIT
Using TFS I've stepped back in my history a couple of revs - it seems like there's an additional field I added recently that's breaking the query. When I comment out that field and call my sproc, it works fine.
I don't get why, though - it's just a varchar(255) field. I've got plenty of other fields in this database that are set up in similar ways. Any thoughts as to why this would be a problem?
EDIT
Using SQL Profiler, I can see the statement execute AND commit...but still, no data updates. I'm wondering whether I need to trash the sproc and start over again?
Run the stored procedure without the .Net code (i.e directly in SQL Server Management Studio) and see whether the changes are updated or not. Probably you are missing an explicit commit statement.
May sound stupid, but if you are out of disk space I've seen SQL server go through the motions, no errors but your data does not get saved. Easy to check too!
Try to set CommandType like that :
SqlCommand cmd = new SqlCommand("mystoredprocedure",myConnection)
cmd.CommandType = CommandType.StoredProcedure
Try to use:
SqlCommand cmd;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
or you maybe use:
CALL mystoredprocedure(#ParameterName)
as SQL-Text
try this !
SqlCommand cmd = new SqlCommand(string.Format("mystoredprocedure('{0}')",inputValue),myConnection)
Try to run sp directly from SQL SERVER and remove error handling from stored procedure to get the exact error in .Net.
Can you try one simple thing for me?
Change your stored procedure to accept no parameter. Change logic of stored proc to just insert one row in one table and then change your code to call that procedure and find out whether call is successful or not.
I think that you use a wrong way to call a stored procedure. The value -1 returned by ExecuteNonQuery is because of the statement: if INSERT/UPDATE/DELETE the value is the number of rows affected, -1 if there's a rollback. In all the other cases the return value is -1 (your case, I think).
The SqlCommand constructor when used with the two parameters SqlCommand(String, SqlConnection) needs that the first one is a generic query so you can run something like "exec myProcedure #par1" and the parameters can be set e.g.:
Dim par1 As New SqlParameter("#par1", SqlDbType.VarChar, 50)
par1.Value = "DummyValue"
cmd.Parameters.Add(par1)
But in the ideal situation, when you've to call a stored than you've to set the CommandType to "StoredProcedure", like then MSDN suggests in this link http://msdn.microsoft.com/it-it/library/yy6y35y8.aspx.
(I will show you VB code... sorry.. it's easily converted to C# with tools like this.)
If you want to read a value from the stored procedure that you run, you can populate a datased (for example, "ds") using a SqlAdapter -this is only an example-:
Dim da As New SqlDataAdapter(cmd)
da.Fill(ds, "result")
If ds.Tables.Item("result").Rows.Count > 0 Then
Return True
Else
Return False
End If
If you don't need to read anything you can simply use:
cmd.ExecuteNonQuery()
Surely you've to tell that you want to launch a stored procedure:
cmd.CommandType = CommandType.StoredProcedure
Hope to be useful to you...
Bye, Massimo.
I think you are missing Command Type while creating Command object.. Set command type of command object as StoreProcegure and then check again.. Since if u dont set command type then ur query execute but u wont get any error and required result also.
From your code I can see that the parameter name you are passing is not the same that you are using in you procedure.

SQL Server: way to see final query with filled parameters

Is there a way to see final query which is passed to SQL Server database from my C# app ?
For ex I got query:
SELECT * FROM mytable WHERE x = #yyyy;
This creates and SQLCommand object
SqlCommand cmd = new SqlCommand("SELECT * FROM mytable WHERE x = #yyyy");
Plus I need to pass parameter:
cmd.Parameters.Add("#yyyy","MyValue");
What I want to see (in debug in C# or somewhere in SQL Server Management Studio) is this:
SELECT * FROM mytable WHERE x = MyValue
Where can I find such query ?!
Best regards
Where can I find such query ?!
You can't. Such a query never exists. The values are not substituted into the SQL.
I think actually sp_executesql is called, and this function accepts the parameters separately from the SQL. You can check this using SQL Profiler to see the actual SQL.
Update:
ORDER BY #descOrAsc
Your problem is that parameters can only be used in certain places where expressions are allowed. DESC is not an expression - it is a reserved word. You cannot use a parameter containing the string "DESC" instead of writing the keyword DESC in the query.
Also, you haven't specified which column to order by.
You can run the SQL Server Profiler and see all the queries that get executed, to see whats happening (and copy paste these into the Sql Server Management Studio to do tests etc)
I would expect the query to be passed to SQL Server with the parameters. There should be no need for anything to ever create a full SQL-only query. It makes no sense to do so, as it just means more conversions for either the client, the server or both. On the server side, the query processor is going to want to parse the query into clauses with values - if the command can pass those values directly, where's the advantage on converting them into the SQL statement, only to have the server parse them into separate values again?
1.You can use SQL Profiler. (here you can see all process)
2.You can write all your queries to SQL Server table. And then you can always get queries from this table.

Getting ##IDENTITY from TableAdapter

I am trying to complete a seemingly simple task that has turned into a several hour adventure: Getting ##Identity from TableAdapter.Insert().
Here's my code:
protected void submitBtn_Click(object sender, EventArgs e)
{
AssetsDataSetTableAdapters.SitesTableAdapter sta = new AssetsDataSetTableAdapters.SitesTableAdapter();
int insertedID = sta.Insert(siteTxt.Text,descTxt.Text);
AssetsDataSetTableAdapters.NotesTableAdapter nta = new AssetsDataSetTableAdapters.NotesTableAdapter();
nta.Insert(notesTxt.Text, insertedID, null,null,null,null,null,null);
Response.Redirect("~/Default.aspx");
}
One answer suggests all I may have to do is change the ExecuteMode. I tried that. This makes GetData() quit working (because I'm returning a scalar now instead of rowdata) (I need to keep GetData()). It also does not solve the issue in that the insertedID variable is still set to 1.
I tried creating a second TableAdapter in the TypedDataSet.XSD and setting the property for that adapter to "scalar", but it still fails with the variable getting a value of 1.
The generated insert command is
INSERT INTO [dbo].[Sites] ([Name], [Description]) VALUES (#Name, #Description);
SELECT Id, Name, Description FROM Sites WHERE (Id = SCOPE_IDENTITY())
And the "Refresh the Data Table" (adds a select statement after Insert and Update statements to retrieve Identity" is also set.
Environment
SQL Server 2008 R2, Visual Studio 2010, .NET 4, Windows XP, all local same machine.
What's causing this?
EDIT/UPDATE
I want to clarify that I am using auto-generated code within Visual Studio. I don't know what the "tool" that generated the code is, but if you double click the *.XSD file it displays a UI of the SQL Table Schema's and associated TableAdapter's. I want to keep using the auto-generated code and somehow enable getting the Identity. I don't want to write this all by hand with stored procedures.
The real answer:
read the notes below!
Get identity from tableadapter insert function
I keep getting questions about this issue very often and never found
time to write it down.
Well, problem is following: you have table with primary key with int
type defined as Identity and after insert you need to know PK value of
newly inserted row. Steps for accomplishing to do this are following:
use wizard to add new insert query (let's call it InsertQuery) in the
body of query just add SELECT SCOPE_IDENTITY() at the bottom after
saving this query, change ExecuteMode property of this query from
NonQuery to Scalar in your code write following (ta is TableAdapter
instance) :
int id;
try
{
id = Convert.toInt32(ta.InsertQuery(firstName, lastName, description));
}
catch (SQLException ex)
{
//...
}
finally
{
//...
}
Make money with this! :) Posted 12th March 2009 by Draško Sarić
From:
http://quickdeveloperstips.blogspot.nl/2009/03/get-identity-from-tableadapter-insert.html
Notes:
Setting the ExecutMode to Scalar is possible via the Properties of your generated Insert Query. (press F4).
In my version (Visual Studio 2010 SP1 ) the select statement was generated automatically.
Here's my SQL Code that works.
CREATE PROCEDURE [dbo].[Branch_Insert]
(
#UserId uniqueidentifier,
#OrganisationId int,
#InsertedID int OUTPUT
)
AS
SET NOCOUNT OFF;
INSERT INTO [Branch] ([UserId], [OrganisationId])
VALUES (#UserId, #OrganisationId);
SELECT Id, UserId, OrganisationId FROM Branch WHERE (Id = SCOPE_IDENTITY())
SELECT #InsertedID = SCOPE_IDENTITY()
Then when I create the Table Adapter - I can instantly see the #InsertedID parameter.
Then from code, all I do is:
int? insertedId = 0;
branchTA.Insert(userId, orgId, ref insertedId);
I'm not 100% whether using ref is the best option but this works for me.
Good luck.
All of the info is here, but I didn't find any single answer complete, so here is the complete steps I use.
Add an insert query, and append SELECT SCOPE_IDENTITY() to it, like so:
INSERT INTO foo(bar) VALUES(#bar);
SELECT SCOPE_IDENTITY()
Make sure you add a ; to the end of the INSERT statement that VS creates for you.
After you Finish the add query wizard, make sure the query is selected in the design view then change Execute Mode to Scalar from the properties pane.
Make sure you use Convert.ToInt32() when you call the query from your code, like so:
id = Convert.ToInt32( dataTableAdapter.myInsertQuery("bar") )
You will not get compiler errors without the Convert.ToInt32, but you will get the wrong return value.
Also, any time you modify the query, you have to reset the Execute Mode back to Scalar, because VS will change it back to Non Query every time.
Here's how you do it (in the visual Designer)
Right Click the Table Adapter and "Add Query"
SQL Statements - Choose Update (best auto-gen parameters)
Copy and paste your SQL, it can be multi-line, just make sure that the "Query Designer" doesn't open up, as it will not be able to interpret the multiple commands - my example shows a sample "merge" set of statements (note that new SERVERS have Merge commands).
UPDATE YOURTABLE
SET YourTable_Column1 = #YourTable_Column1, YourTable_Column2 = #YourTableColumn2
WHERE (YourTable_ID = #YourTable_ID)
IF ##ROWCOUNT=0
INSERT INTO YOURTABLE ([YourTable_Column1], [YourTable_Column2])
VALUES (#YourTable_Column1, #YourTable_Column2)
#YourTable_ID = SCOPE_IDENTITY()
Change/Add the #YourTable_ID Parameters from the query properties window/sidebar. In the Parameter Collection Editor, The ID parameter needs to be have a Direction of InputOutput, so that the value gets updated when the Table Adapter function is called. (Special note: Make sure that whatever column you make InputOutput that the designer doesn't have this column as "Read Only" and that the data types match up as well, otherwise change the column in the datatable, or the parameter information accordingly)
This should save the need of writing a Stored procedure for such a simple activity.
Much Wow. You will notice that this method is a fast way of doing Data Layer functions without having to break into the SQL procedures and write up a ton of Procedures. The only problem, there is a lot of dancing you have to do...
You'll need to setup the insert to return the identity as an output value and then grab it as a parameter in your adapter.
These two links should get you going:
http://www.akadia.com/services/dotnet_autoincrement.html
http://msdn.microsoft.com/en-us/library/ks9f57t0.aspx
You have exactly two choices:
change your SQL code manually
use whatever Visual Studio generates
I'd use the following SQL and ExecuteScalar.
INSERT INTO [dbo].[Sites] ([Name], [Description])
OUTPUT INSERTED.ID
VALUES (#Name, #Description);
One way is to run a select query after the insert command. A good way is to wrap the original command like this:
public int WrapInsert(Parameters)
{
.....
int RowsAffected = this.Insert(..Parameters..);
if ( RowsAffected > 0)
{
try
{
SqlCommand cm = this.Connection.CreateCommand();
cm.CommandText = "SELECT ##IDENTITY";
identity = Convert.ToInt32(cm.ExecuteScalar());
}
finally
{
....
}
}
return RowsAffected;
}

Dataset times out while query runs immediately

I am running a query directly, it is trivial in nature:
SELECT * FROM [dbo].[vwUnloadedJobDetailsWithData] WHERE JobId = 36963
When I run this from Management studio the query doesn't even take a second. When I run it from within the table adapter it times out. I have fixed this multiple times, but the fix is ludicrous. If I delete the table adapter from my xsd file and recreate it the query time matches that of management studio for about two days, but I have to redeploy which is asinine.
Any insight into what could be causing this would be greatly appreciated. I've seen another question about this but the solution involving set arithabort on before the query had no effect for me.
Edit: It was asked that I show my code for calling the query. Now this happens when I go into my xsd file and just do preview data as well, but for sake of clarity, here it is:
using (TEAMSConnection connection = new TEAMSConnection())
{
connection.OpenConnection();
_JobDetailsDAO jobDetailDao= new _JobDetailsDAO(connection);
return jobDetailDao.GetUnloadedJobDetailsByJobId(jobId);
}
On disposal of connection the database connection is closed. using this line of code:
if (_DBConnection != null && _DBConnection.State == ConnectionState.Open)
_DBConnection.Close();
Edit2: I ran a trace and here are the set options that are being set
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language us_english
set dateformat mdy
set datefirst 7
set transaction isolation level read committed
I went and added that to the query that I generated in management studio and it still ran in less than a second. I even copied the query exactly as in the trace.
exec sp_executesql N'SELECT * FROM [dbo].[vwUnloadedJobDetailsWithData] WHERE JobID = #JobId',N'#JobId int',#JobId=36963
and it is still less than a second return time. I am so very confused.
Thanks,
Josh
the most likely scenarion why this would be happening is the difference in SET options between ssms and ado.net. that difference causes (re)building of execution plans that might not be optimal.
Alright, well I could not find any solution that would continue to allow me to use the dataset, so I went straight to using the SqlDataAdapter in code rather than using the auto generated TableAdapters.
According to the trace it performs the exact same query, but so far it works. It may not in two days, but for now it works it seems.
Just trying to think loudly:
Maybe there is a lock caused by another process/person? Is there anybody who updates the same row at the same time? Is there anybody who opens the table from Management studio or Query Analyzer with Open Table feature and plays with the filters?
Try looking for locks using sp_who2
Some thoughts:
What I'd call parameter sniffing for stored proc. Try the OPTION (RECOMPILE) hint, so your sent SQL looks like this:
exec sp_executesql
N'SELECT *
FROM [dbo].[vwUnloadedJobDetailsWithData]
WHERE JobID = #JobId
OPTION (RECOMPILE)',
N'#JobId int',
#JobId=36963
Explanation: When a query plan is produced and cached, it may be a bad, atypical value. Say JobID is usually very selective, but for that one execution it's not. When you run the query the next plan the cached plan is wrong for the next selective JobId. A plan will be recompiled for various reasons, but the value on recompilation matters.
Otherwise, what is the exact datatype of Jobid? If it's smallint, then the column will be converted to int in the parameterised query. When using a constant it will be smallint. Make sure the type is defined correctly: this matters in SQL code.

Categories

Resources