This question already has answers here:
How to invoke the job in SQL Server agent from windows application
(6 answers)
Closed 6 years ago.
Inside SQL Server Management Studio there are more than just databases listed in the Object Explorer. Under SQL Server Agent, we have "Jobs". One of these jobs that we have updates the client to match the cache. This is important because of how our cache system works. If we make a change to the database, it is not reflected if we run this job.
So, in the C# code, there are times when I make a change to a database table that I need to run this job afterwards. It is easy to do in SQL Server Management Studio. I just right click on the job and click on "Start Job at Step..." but how would I do the same thing in C#?
The problem I have been having is not answered in what might be a duplicate post. The command line is "execute msdb.dbo.sp_start_job #job_name='Update Client Matching Cache'" and, while I have permissions to run this command from the SQL line (thus showing I have permissions), I cannot run it from the code. Passing the job name, "update client matching cache" to this procedure fails to run:
public static void RunStoredProcedure(string strSQLJob)
{
SqlCommand ExecJob = new SqlCommand();
ExecJob.CommandType = CommandType.StoredProcedure;
ExecJob.CommandText = "msdb.dbo.sp_start_job";
ExecJob.Parameters.AddWithValue("#job_name", strSQLJob);
using (SqlConnection sc = DatabaseManager.SqlConnection())
{
sc.Open();
using (ExecJob)
{
ExecJob.Connection = sc;
ExecJob.ExecuteNonQuery();
}
}
}
The error is: An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code
Additional information: The EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'.
I also get the same error if I open Visual Studio in admin mode.
You need to use Microsoft.SqlServer.Management.Smo.Agent namespace..In this namespace you have job class which has INVOKEmethod.Here is some sample code from MSDN..
Server srv = new Server("(local)");
Job jb = new Job(srv.JobServer, "Test Job");
jb.Create();
JobStep jbstp = new JobStep(jb, "Test Job Step");
jbstp.OnSuccessAction = StepCompletionAction.QuitWithSuccess;
jbstp.OnFailAction = StepCompletionAction.QuitWithFailure;
jbstp.Create();
jb.ApplyToTargetServer(srv);
jb.IsEnabled = true;
jb.Invoke();
You can create a new job and a new "Task" table.
The new job would be checking the status of the "Task" table every 5 minutes or so. If there is a new row in that table with a status, for example: "pending", then, this job will start the target job, and will change the status to "in progress".
Finally, the last job can include a step to change the status again to "success" or "failure" when it's finished.
Using the answer in a similar question almost works apart from a privilege error being thrown How to invoke the job in SQL Server agent from windows application
Related
Basically every time I run my game MS SQL database crashes and returns this error message.
Cannot open database "C:\USERS\ME\SOURCE\REPOS\A GIRL CALLED LORRY\A GIRL CALLED LORRY\DATABASE.MDF" requested by the login. The login failed.
Login failed for user 'me-PC\me'.
I did not change any of the SQL or C# code in my project to cause this error. All I did was simply modify a table within my database by adding a new column of type string.
I've tried using SMSS to open my DataBase.mdf file within my project to see if my user has privileges to access it, however I was unable to open my DataBase.mdf file because it wouldn't even show up within SMSS. So I'm not sure how I can get privileges to access my database again. I also tried removing all the changes I've added to the DB which caused the error in the first place however the error still persists.
As I've said, the error was caused by modifying a table within my database, but there is a small piece of code where the game crashes as soon as I attempt to open the database to remove data:
//this method is used to initialize the database.
public static void createSave() {
//database stuff:
con = new SqlConnection("Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=C:\\Users\\me\\source\\repos\\A Girl Called Lorry\\A Girl Called Lorry\\Database.mdf;Integrated Security=True");
adp = new SqlDataAdapter();
ds = new DataSet();
Console.WriteLine("we are in!");
//the below code only initializes if isNewGame is set to true.
removeAllFromInventory();
rewriteCurrentObjects();
loadDefaultNpcs();
}
//removeAllFromInventory is where it crashes.
//removes all items from inventory:
public static void removeAllFromInventory() { //this only applies if
//isNewGame is set to true since we want to wipe the inventory in a new game
if (!isNewGame) return;
con.Open(); //here is where it crashes.
adp.SelectCommand = new SqlCommand("DELETE FROM curInventoryItems", con);
adp.SelectCommand.ExecuteNonQuery();
con.Close();
}
However I was unable to open my DataBase.mdf file because it wouldn't even show up within SMSS. So I'm not sure how I can get privileges to access my database again. I also tried removing all the changes I've added to the DB which caused the error in the first place however the error still persists.
There is confusing part in your question, when you unable to connect .MDF how could you remove changes that was added into DB.
However, following steps might be helpful to get your database back to normal:
Verify the account (me-PC\me) has permissions on C:\USERS\ME\SOURCE\REPOS\A GIRL CALLED LORRY\A GIRL CALLED LORRY\DATABASE.MDF
If doesn't work after the permissions, you can troubleshoot the SQL Localdb connections using these steps
Install SQL Express (as it's difficult to manage with LocalDB database engine), and attach Database.mdf into SQL Express engine. You can do this using following command via SSMS
Once your database ready at SQL Express, you can change your connection string to "Data Source=Localhost\\SQLEXPRESS;Initial Catalog=YourNewDBName;Integrated Security=True"
In case issue even with SQL Express, you may follow these steps..
--- You need to move "Database.mdf" and ".ldf" files into "C"\SQLData" folder before executing the command
CREATE DATABASE YourDatabase
ON (FILENAME = 'C:\SQLData\Database.mdf'),
(FILENAME = 'C:\SQLData\Database_log.ldf')
FOR ATTACH;
I am trying to setup my .NET 4.7.1 program that is connecting to a MySQL database 8.0 to use the minimum privileges to run.
The .NET program is using MySql.Data to make connection. The minimum right for a user to execute a stored procedure is typically only EXECUTE privilege. This works fine from MySQL workbench or command line.
Upon running the .NET program this does return the following exception:
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
To make it easy, I have create a very small demo program to demonstrate the issue.
Setup of the database:
CREATE DATABASE Spike;
CREATE PROCEDURE TestAccess()
BEGIN
END;
CREATE USER Spike#localhost IDENTIFIED WITH mysql_native_password BY 'sample';
GRANT EXECUTE ON PROCEDURE `TestAccess` TO Spike#localhost;
Setup program code:
static void Main(string[] args)
{
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample"))
{
conn.Open();
Console.WriteLine("Connection open");
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = "TestAccess";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
Console.WriteLine("Query executed");
}
Console.ReadKey();
}
The crash happens at the line cmd.ExecuteNonQuery();
The stack from the crash is interesting, since it seems to indicate that the information_schema is queried. When logging all statements I can see that the last statement before the exception is:
SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess'
I cannot grant different rights on information_schema, but I could give more rights on the stored procedure to make more information visible in the routines table, this feels wrong however. Simple tests with granting CREATE and ALTER access also did not work.
Is there something else I can do, without granting too much privileges?
This appears to be a bug in Connector/NET, similar to bug 75301 but a little different. When it's trying to determine parameter metadata for the procedure, it first creates a MySqlSchemaCollection named Procedures with all metadata about the procedure. (This is the SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess' query you see in your log.)
The Spike user account doesn't have permission to read the ROUTINE_DEFINITION column, so it is NULL. Connector/NET expects this field to be non-NULL and throws a SqlNullValueException exception trying to read it.
There are two workarounds:
1) The first, which you've discovered, is to set CheckParameters=False in your connection string. This will disable retrieval of stored procedure metadata (avoiding the crash), but may lead to harder-to-debug problems calling other stored procedures if you don't get the order and type of parameters exactly right. (Connector/NET can no longer map them for you using the metadata.)
2) Switch to a different ADO.NET MySQL library that doesn't have this bug: MySqlConnector on NuGet. It's highly compatible with Connector/NET, performs faster, and fixes a lot of known issues.
I found an answer with which I am quite pleased. It is changing the connection string by adding CheckParameters=false:
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample;CheckParameters=false"))
This disables parameter checking, and thereby information_schema queries.
This question already has answers here:
Why saving changes to a database fails?
(2 answers)
Closed 5 years ago.
:)
I've started with project of creating some program for Library. I mean, it is a simple program which has login form and some features for admin. Also, I've done database (everything is done with Visual Studio 2013), SQL Service-based Database. I followed some Youtube tutorials and now when I added button for adding users in database I run into "problem". This is code for Add button:
private void btnAdd_Click(object sender, EventArgs e)
{
string connectionString = ConfigurationManager.ConnectionStrings["Library.Properties.Settings.KnjiznicaDBConnectionString"].ConnectionString;
string query = "INSERT INTO User VALUES(#Name,#Surname,#Year,#Mail)";
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(query, connection);
{
connection.Open();
command.Parameters.AddWithValue("#Name", txtName.Text.Trim());
command.Parameters.AddWithValue("#Surname", txtSurname.Text.Trim());
command.Parameters.AddWithValue("#Year", txtYear.Text.Trim());
command.Parameters.AddWithValue("#Mail", txtMail.Text.Trim());
command.ExecuteScalar();
}
}
Now, I know that user is added into database, because I can see it in DataGridView which is also in Form, but when I check directly in Database (I mean in Server Explorer->Database_name->Tables->User (Show Table Data)), that new user is actually not added there. And no matter if I exit Visual Studio, as long as I don't shut down computer, that new User will be in DataGridView but not in "Database". And when I restart computer and start Visual Studio again, new user won't be even in DataGridView. Only permanent users are those that I add directly through Show Table Data or with New Query also in Server Explorer.
I would like to know what should I correct so all users added through the code and Form are implemented in "real Database" not just DataGridView.
Thanks :)
Wrong command
You need SqlCommand.ExecuteNonQuery
And you would be wrapping open and command in Using blocks
I am running into issues working with a very large table from C# .Net 4.0.
For reference the table has ~120 Million rows.
I can't do even a simple query like
SELECT TOP(50) *
FROM TableName
WHERE CreatedOn < '2015-06-01';
From code it will timeout (Default setting - 15 seconds I believe), but in SSMS it is instant.
There is an index on the column in the WHERE clause. I have also tried explicitly casting the string to a DateTime, and using a DateTime parameter instead of a literal value.
I tried a different query that filters by the PK (bigint, identity, clustered index) If I do something like "Where TableRowID = 1" it works fine from code, but if I try to use "<" or "<=" instead it will timeout (returns instantly in SSMS), regardless of how many rows are turned.
The execution plans are very simple and are exactly the same.
I have tried changing ARITHABORT but that has had no effect.
I tried having the Application connect with my own account (SSPI) instead of its own credentials with no effect.
I have been researching this issue for a few days, but everything I have found blames different execution plans.
Does anyone have any idea what could be causing this issue?
The .Net code looks like this:
private DataSet ExecuteQuery(string query, string db, List<SqlParameter> parms = null)
{
string connectionString = ConfigurationManager.ConnectionStrings[db].ToString();
SqlConnection con = new SqlConnection(connectionString.Trim());
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
try
{
con.Open();
DataSet ds = new DataSet();
sqlDataAdapter.SelectCommand = new SqlCommand(query, con);
sqlDataAdapter.SelectCommand.CommandType = CommandType.Text;
if (parms != null)
{
foreach (SqlParameter p in parms)
{
sqlDataAdapter.SelectCommand.Parameters.Add(p);
}
}
sqlDataAdapter.Fill(ds);
if (ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
return ds;
}
return null;
}
finally
{
if (sqlDataAdapter != null)
sqlDataAdapter.Dispose();
if (con != null)
con.Dispose();
}
}
The error message I get in .Net is the standard timeout message:
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Here are my experience when dealing the issues.
Very C# sql code passed to sql server is
SELECT TOP(50) *
FROM TableName
WHERE CreatedOn < '2015-06-01'
Make sure the criteria. If it takes "instant time" to retrieve records on SSMS, the sql statement and db optimization is ok.
As other people have pointed out, you should post your C# codes and see what happens. There could be other issues. Could that be network? Could that be web.config? Do you call directly from C# code? Do you call via web service?
when you said time out? Does it time out at the time you execute the query. There is very little information you provide. Do you use third party routines (such as written by vendor or your company) to execute queries? If it possible, put the break point at the code that execute sql statement. What I mean is dig all the way to native codes, and put the break codes.
120 million records. Looks like the database has be optimized if it runs very fast on SSMS. I would take look outside SQL server.
good luck
My first step there would be to look at what your code is sending to the sql server. I'd begin by running the sql profiler. if you're not familiar with it. Here is a link on how to use it.
https://www.mssqltips.com/sqlservertip/2040/use-sql-server-profiler-to-trace-database-calls-from-third-party-applications/
After this you may want to look into network traffic times between the 2 servers.
Then look at IIS and see how it's setup. Could be a setting is wrong.
Check the error logs and see if you have any errors as well.
When you execute code in SSMS, the system is setting some default values on your connection. Specifically, look at Tools --> Options --> Query Execution --> Sql Server --> Advanced (and also ANSI). These statements are executed on your behalf when you open a new query window.
When you create your connection object in C#, are you setting these same options? If you don't explicitly set them here, you are taking the default values as defined in the actual SQL Server instance. In SSMS, you can get this by viewing the properties of the server instance and choosing the Connections page. This shows the default connection options.
You can also get this information without using the UI (you can do this in a separate application that uses the same connection string, for example). This article on MSSQLTips should guide you in the right direction.
I run a simple query to SQL and can't seem to get it working correctly.
DataTable loDTDOffre = new DataTable();
SqlCommand loSQLCommand = new SqlCommand("dbo.SP_StoredProc", loConnectionBD.ConnectionSql);
loSQLCommand.CommandType = CommandType.StoredProcedure;
loSQLCommand.Parameters.Add("#liNoUnit", SqlDbType.Int);
loSQLCommand.Parameters["#liNoUnit"].Value = noUniteProduction;
SqlDataAdapter loSqlDataAdapter = new SqlDataAdapter(loSQLCommand);
loSqlDataAdapter.SelectCommand = loSQLCommand;
loSqlDataAdapter.Fill(loDTDOffre);
My database connection is open, the stored proc executed in SQL Management Studio works fine. All I get as error message in VS2010 is :
Warning: Fatal error 50000 occurred at May 30 2013 11:17AM. Note the error and time, and contact your system administrator.
Process ID 59 has raised user error 50000, severity 20. SQL Server is terminating this process.
Is there any way to get a clearer message of what is wrong, the code seems right. The error message is so general, I can't figure out what I do wrong.
My stored procedure returns a simple select, one row.
Thanks
Turns out it runs on an approle, this came out :
The SELECT permission was denied on the object 'thisTable', database 'thisDatabase', schema 'dbo'.
Fixed, thank you.