I am following tutorial on https://msdn.microsoft.com/en-us/library/jj943772.aspx
Has anyone finished this project?
When I am doing it, the buttons in navigation don't seem to respond...any help will be very welcome.
Another issue is as follows:-
I am sorry Fran Tan, I should have included the code. I thought someone has done it and can show me the right course. Indeed this happened so thank you Alex W. It was matter of double clicking on the buttons to create button click method. I would like to ask: The app has been build and published and when I try to enter a new customer it comes back with the message: 'Customer ID was not returned. Account could not be created'.: //NC-10 try-catch-finally
try
{
//NC-11 Open the connection.
conn.Open();
//NC-12 Run the stored procedure.
cmdNewCustomer.ExecuteNonQuery();
//NC-13 Customer ID is an IDENTITY value from the database.
this.parsedCustomerID = (int)cmdNewCustomer.Parameters["#CustomerID"].Value;
this.txtCustomerID.Text = Convert.ToString(parsedCustomerID);
}
catch
{
//NC-14 A simple catch.
MessageBox.Show("Customer ID was not returned. Account could not be created.");
}
finally
{
//NC-15 Close the connection.
conn.Close();
}
and this is the stored procedure:
CREATE PROCEDURE [Sales].[uspNewCustomer]
#CustomerName NVARCHAR (40),
#CustomerID INT OUTPUT
AS
BEGIN
INSERT INTO [Sales].[Customer] (CustomerName)
VALUES (#CustomerName);
SET #CustomerID = SCOPE_IDENTITY();
RETURN ##ERROR
END
GO
Related
I'm working on rewriting the app we use to run upgrades on our database. Basically the idea of the app is it takes a bunch of scripts (one for each version) and runs each script between the current version of the database and the most recent version it has. I'm trying to find a better way for us to handle this process and I tried to make SQL Management Objects work the way we need them. For reference, here are the limitations I have to work with.
It has to handle GO statements (which SMO does)
It can't require us to modify the files we have. (This will be used with hundreds, maybe thousands of files and we don't want to have to go edit each one of them manually, so adding try catches are kinda out of the question)
It has to continue to the next GO statement if it encounters an error. This is mostly to match the way our current app works. If an error is encountered in one of the batches of the script we want it to continue on to the next one since they are most of the time unrelated.
If the script encounters an error, it has to output an error message so the user can know a version's upgrade didn't work, and so the developers can correct the error for the next version (here is the problem)
Here's what I currently have as a code:
string messages = "";
private void button1_Click(object sender, EventArgs e)
{
string setup = File.ReadAllText(#"[redacted]\Setup.sql");
string script = File.ReadAllText(#"[redacted]\6.3.6002.0.sql");
string script2 = File.ReadAllText(#"[redacted]\6.3.6003.0.sql");
var cnx = new SqlConnection(/*proper connection string*/);
var server = new Server(new ServerConnection(cnx));
//server.ConnectionContext.InfoMessage += ConnectionContext_InfoMessage;
server.ConnectionContext.ServerMessage += ConnectionContext_ServerMessage;
server.ConnectionContext.ExecuteNonQuery(setup);
server.ConnectionContext.ExecuteNonQuery(script);
server.ConnectionContext.ExecuteNonQuery(script2, ExecutionTypes.ContinueOnError);
txtResult.Text = messages;
}
private void ConnectionContext_ServerMessage(object sender, ServerMessageEventArgs e)
{
messages += e.Error.Message + "\r\n";
}
And here are the scripts I'm using:
Setup.sql:
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'UPGRADE_HISTORY')
DROP TABLE UPGRADE_HISTORY
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'TEST_CODE_TABLE')
DROP TABLE TEST_CODE_TABLE
CREATE TABLE UPGRADE_HISTORY (
UPDATE_DATE DATE NOT NULL,
VERSION_TXT VARCHAR(50) NOT NULL,
PRIMARY KEY (UPDATE_DATE, VERSION_TXT)
)
CREATE TABLE TEST_CODE_TABLE (
CODE_VALUE INT PRIMARY KEY,
DESCRIPTION_TXT VARCHAR(250) NOT NULL
)
INSERT INTO UPGRADE_HISTORY VALUES
(DATEADD(d, -3, GETDATE()), '6.2.5000'),
(DATEADD(d, -1, GETDATE()), '6.2.5001'),
(DATEADD(d, -1, GETDATE()), '6.2.5002'),
(DATEADD(d, -1, GETDATE()), '6.3.6000.0'),
(DATEADD(d, -1, GETDATE()), '6.3.6001.0')
INSERT INTO TEST_CODE_TABLE VALUES
(1001, 'Test Code Table'),
(1002, 'Test Code Table 2')
6.3.6602.0.sql:
INSERT INTO UPGRADE_HISTORY VALUES
(GETDATE(), '6.3.6001.0')
GO
PRINT 'Test Code Table Change'
GO
UPDATE TEST_CODE_TABLE SET DESCRIPTION_TXT = 'Test Code Table Change' WHERE CODE_VALUE = 1002;
GO
6.3.6003.0.sql:
INSERT INTO UPGRADE_HISTORY VALUES
(GETDATE(), '6.3.6003.0')
GO
PRINT 'Test Error'
GO
INSERT INTO CODE_TABLE VALUES (1001, 'Test')
--This will throw an error since this will conflict with the primary key
--of the code table (or you know, because I just noticed it doesn't call
--the right table, it's really relevant since I want it to throw an
--error, w/e what it is)
GO
PRINT 'Second Test Code Table Change'
GO
UPDATE TEST_CODE_TABLE SET DESCRIPTION_TXT = 'Test Code Table Change 2' WHERE CODE_VALUE = 1002;
--We still want this to execute.
GO
This is to reproduce a situation that can happen in our updates. So, as it is, the setup is only to create recreate the database each time so I can use the same scripts, then the first upgrade file is to simulate a functioning as intended file, then finally the 2nd upgrade file is to simulate an upgrade file that has an error. And this is where the problems start. As I've got it working at the moment, when the second script is executed, the first part runs, then the second part runs and errors out, but I don't get an error message. Neither the InfoMessage nor the ServerMessage events get fired. Then the third part runs (the one after the statement that errors out), and I get a ServerMessage for the print. For reference, here's the output I'm receiving:
Test Code Table Change
Test Error
Second Test Code Table Change
The print before and after the errors happen, and I can confirm from double checking the data that the UPDATE statement after the error is also executed. However, no message or error is thrown for the fact that the INSERT statement throws an error. We would really need to have SMO throw an error, or trigger the ServerMessage event, or anything really. Is there something I'm missing, or is this a shortcoming of the framework.
I have a SQL stored procedure which uses openrowset command and fetches values from an excel sheet and inserts it into the database.
I have created a C# application which will call the procedure and execute it.
PROBLEM!
When I execute the procedure from SQL management studio, there are no errors. It happens perfectly. But when I execute it through the C# application I get an error: "Conversion failed when converting date and/or time from character string."
Code
SQL Query (only the insert part)
insert into tbl_item ([Item code],[Dt Created])
select[Item code] ,
case when [Dt Created] is null or [Dt Created]='' then null when ISDATE(CONVERT(nvarchar,CONVERT(datetime, [Dt Created],103))) =1 then CONVERT(datetime, [Dt Created],103) else null end as [Dt Created]
FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0','Excel 12.0; Database=C:\Upload\Report.xlsx;HDR=YES;IMEX=1;',
'select * from [Sheet1$]')
C# Code
public int updateItem()
{
SqlCommand cmd; cmd = new SqlCommand("usp_updateItem", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
try
{
if (conn.State.Equals(ConnectionState.Closed))
conn.Open();
cmd.ExecuteNonQuery();
ret = Convert.ToInt32(returnParameter.Value);
}
catch (Exception e)
{
err = "Error: " + e.Message;
return -1;
}
finally
{
conn.Close();
}
return ret;
}
What is the format you are having in the [Dt Created] variable.
the convert statement you have in the case will convert only the following types below
YYYY-MM-DD
YYYY-DD-MM
DD-MM-YYYY
The error you are getting is since you have a date in the format of "MM-DD-YYYY" something like '12-24-2015'. Due to this you are getting the conversion error.
Excuse me I want to stop you here. Your problem has resolved now but whatever
Karthik Venkatraman had said is correct. Somehow you got solution but for learning purpose i recommended to investigate little bit more. This is not belongs to the whatever you have said but damm sure this belongs to date-format.
**
One trick
Create one DateTimeVariable and once its initialized then just parse it using DateTimeParse class according to the records exist in database.
I am sure you will get solution.. Thanks :)
This is how I finally solved it...
The SQL error message 'Failed Conversion' was absolutely a wrong pointer. It had no connection to the issue at hand. [If only I knew this before :( ]
The actual problem was that I had called another procedure within the main procedure I had posted above. This setup ran perfectly in SQL management studio which was running under my credentials. Now in the C# application, I had created another SQL login user ID to run it. And this user ID did not have execute permission to run the sub procedure. And ironically, SQL gave me a misleading conversion error. Once I gave the right permission it worked perfectly.
I am currently writing my first .Net & C# application with Visual Studio, and have a need to write generated values to MySQL from the application.
At present, I can write values fine - but I need to be able to check to see if a value exists and display that line if it does exist, otherwise insert new line to table. My connection string is defined at the top of the form.
I have the following defined already, and it writes to the database successfully if no duplicate values exist in the LicenseKey column. If a duplicate exists, it throws an unhandled exception.
private void SaveDetails()
{
// MySQL 'insert' command
string InsertNewLicense = "insert into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values('" +this.textBoxLicenseeName.Text+ "','" +this.textBoxComputerName.Text+ "','" +this.textBoxContactName.Text+ "','" +this.textBoxContactEmail.Text+ "','" +this.textBoxLicenseKey.Text+ "','" +this.textBoxCreationDate.Text+ "');";
//MySQL instance details
MySqlConnection InsertLicenseDetails = new MySqlConnection(LicenseDatabaseConnection);
//MySQL command execution
MySqlCommand InsertCommand = new MySqlCommand(InsertNewLicense, InsertLicenseDetails);
// Handles command outputs.
MySqlDataReader InsertReader;
//Opens connection to run query on database
InsertLicenseDetails.Open();
// Here our query will be executed and data saved into the database.
MessageBox.Show("License Details Saved. Please ensure you have emailed the license to the customer.");
while (InsertReader.Read())
{
}
InsertLicenseDetails.Close();
}
What I want to happen is for a check to be run on the LicenseKey column to see if the value exists, before different actions are taken.
If the value does not exist, I would like to insert the new line to the table (like my existing command does).
If, however, the value does exist, I would like to pop up a form showing the values from the line that the duplicate appears in as a form.
Where would I put in an event handler to read MySQLException values? What exception would I have to respond to for a duplicate value or no database response?
I agree with what the others have said in their comments, you could change the SQL Query to do the check instead of having 2.
IF(SELECT ... WHERE A = B)
RETURN THAT THE VALUE ALREADY EXISTS
ELSE
INSERT NEW VALUE
Also there was a good comment about SQL Injection and parameterized queries. The query string should look a bit more like
INSERT into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values(#LicenseeName, #ComputerName, #ContactName ...);
and your SqlCommand be parameterized
InsertCommand.Paramaters.AddWithValue("#LicenseeName", this.textBoxLicenseeName.Text);
InsertCommand.Paramaters.AddWithValue("#ComputerName", this.textBoxComputerName.Text);
...
That should be a good start to get you going.
After looking at the queries for a while I decided to try a different tack - instead of using a direct check if it's there, I opted to use a count(*) query. When I click the save button on the form, the buttonClick_event calls SaveDetails(), which runs the following:
private void SaveDetails()
{
string InsertNewLicense = "INSERT into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values(#LicenseeName, #ComputerName, #ContactName, #ContactEmail, #LicenseKey, #CreationDate)";
string LicenseExistence = "SELECT COUNT(*) FROM BCOM.LicenseDetails WHERE LicenseKey LIKE #LicenseKey";
MySqlConnection LicenseDetails = new MySqlConnection(LicenseDatabaseConnection);
MySqlCommand InsertCommand = new MySqlCommand(InsertNewLicense, LicenseDetails);
InsertCommand.Parameters.AddWithValue("#LicenseeName", this.textBoxLicenseeName.Text);
InsertCommand.Parameters.AddWithValue("#ComputerName", this.textBoxComputerName.Text);
InsertCommand.Parameters.AddWithValue("#ContactName", this.textBoxContactName.Text);
InsertCommand.Parameters.AddWithValue("#ContactEmail", this.textBoxContactEmail.Text);
InsertCommand.Parameters.AddWithValue("#LicenseKey", this.textBoxLicenseKey.Text);
InsertCommand.Parameters.AddWithValue("#CreationDate", this.textBoxCreationDate.Text);
MySqlCommand QueryCommand = new MySqlCommand(LicenseExistence, LicenseDetails);
QueryCommand.Parameters.AddWithValue("#LicenseKey", this.textBoxLicenseKey.Text);
MySqlDataReader InsertReader;
LicenseDetails.Open();
if ((int)(long)QueryCommand.ExecuteScalar() >0)
{
MessageBox.Show("This license already exists in the database.");
}
else
{
InsertReader = InsertCommand.ExecuteReader();
MessageBox.Show("License Details Saved. Please ensure you have emailed the license to the customer.");
while (InsertReader.Read())
{
}
}
LicenseDetails.Close();
So, if the query against the license keys returns with any results at all (more than 0 rows returned), a messagebox pops up showing that the key already exists. If the resultant number of rows is 0, the insert command gets run.
This was figured out with a look through MySQL command notes, testing with phpMyAdmin, matching against existing projects online, and support from the following:
The SELECT query was figured out with great support from #Seige.
The query was parameterized with help from Seige, following on from the advice of Sani Huttunen. Many thanks to them both.
Changing to the count method was done on the advice of a fellow coder in another community online - a good friend and brilliant coder.
We are getting ready for a big SQL migration.
Currently, I have the code written, and I am testing it out with data on my local machine.
Step 1 is to throw out the existing data in the table before I import the new stuff:
using (var txn = m_mySqlConnection.BeginTransaction()) {
using (var cmd = new MySqlCommand("TRUNCATE TABLE `blah_blah`;", m_mySqlConnection, txn)) {
cmd.ExecuteNonQuery();
}
// other code
}
But, the TRUNCATE command is throwing an exception whenever I try to execute it with the MySQL user account I am running the code with:
I tried going into MySQL Workbench to give this userid DROP permission, but all I could find was a way to add DROP under the View section.
I tried that, but it did not work.
How do I go about giving this user the ability to remove the data in these tables so that I can test my populate script?
TRUNCATE deletes the table. Try using DELETE FROM Table.
So, we've got this set of code that, for some reason, keeps timing out. It's not the stored procedure that it's running, because that runs fine. Also, if we remove the parameter from the c# code, the code runs. The parameter keeps breaking (causing it to time out) and we can't figure out why.
c#:
public static PTWViewList GetList(int studynumber)
{
PTWViewList tempList = new PTWViewList();
using (SqlConnection myConnection = new SqlConnection(AppConfiguration.cnARDB))
{
string spName = "ardb.PTWViewSelect";
SqlCommand myCommand = new SqlCommand(spName, myConnection);
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Parameters.AddWithValue("#study", studynumber);
myConnection.Open();
using (NullableDataReader myReader = new NullableDataReader(myCommand.ExecuteReader())) /*this is where the code times out*/
{
tempList = new PTWViewList();
while (myReader.Read())
{
tempList.Add(FillDataRecord(myReader));
}
myReader.Close();
}
}
tempList.ListCount = tempList.Count;
return tempList;
}
stored procedure:
CREATE PROCEDURE [ardb].[PTWViewSelect]
#studynumber int = NULL,
#quoteid uniqueidentifier = NULL,
#lineitemid uniqueidentifier = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT
[Study]
,[LineItemID]
,[QuoteID]
,[Total]
,[COOP]
,[VendorCost]
,[CustCost]
,[LineItemNumber]
,[StudyTypeCode]
,[GroupLeader]
,[PTWDate]
,[PONumber]
,[POStatus]
,[StudyDirector]
,[SL_DESC_L]
,[SL_Code]
,ProjectDescription
,CreatedBy
,chARProcess
,CODate
FROM
[ARDB].[dbo].[PTWView]
WHERE
(#studynumber is null or StudyNumber=#studynumber)
AND (#quoteid is null or QuoteID=#quoteid)
AND (#lineitemid is null or LineItemID = #lineitemid)
END
have you tried
myCommand.Parameters.AddWithValue("#studynumber", studynumber);
instead of:
myCommand.Parameters.AddWithValue("#study", studynumber);
EDIT
If passing parameters is the problem, then it comes down to how much time the stored procedure takes to execute. Default timeout for SQL server is usually 120 secs. You can add "Connect Timeout" to increase timeout in your DB connection string and check out.
** Old Answer -- Ignore **
Without stack trace, and taking your word that the stored procedure is fine, I am guessing that it is timing out due to the connection failure. The code is unable to connect to your DB server and hence timing out.
setting arithabort off made the sp take 45 seconds as opposed to 1. setting it back on changed it back to 1. I updated the stored procedure to set it on, no change in the app. Changed it to off, no change. I then removed the update and then the app worked fine.
I believe what happened is that updating the stored procedure caused it to recompile, fixing the issue. I'm not 100% sure on this though.
One thing could be the ARITHABORT setting, set it to ON...NET defaults to OFF
run the proc in SSMS with ARITHABORT set to OFF and see if it runs slower now like from .NET
example
MyConnection.Execute "SET ARITHABORT ON"
Another thing is that your WHERE clause is not optimal, take a look at Do you use Column=#Param OR #Param IS NULL in your WHERE clause? Don't, it doesn't perform
does the proc run slow with parameters in SSMS? Can you show the execution plan?