How to change size of database - c#

I know how to change size database on SQL (in SQL Server 2005 Express Edition)
ALTER DATABASE Accounting
MODIFY FILE
(NAME = 'Accounting',
SIZE = 25)
How to change size database useing C#?

Submit the DDL via an ExecuteNonQuery command:
mySqlCommand = mySqlConnection.CreateCommand();
mySqlCommand.CommandText =
"ALTER DATABASE Accounting MODIFY FILE (NAME = 'Accounting', SIZE = 25) ";
mySqlConnection.Open();
int result = mySqlCommand.ExecuteNonQuery();
mySqlConnection.Close();
Similar examples can be found here (showing issues related to snapshot isolation, but the ideais basically the same):
http://msdn.microsoft.com/en-us/library/tcbchxcb.aspx

Following example will give you a better overview. Having defined parameters you can pass some stuff that not necessary has to be static. Using using will make sure everything is disposed/closed properly (and or reused if necessary).
public const string sqlDataConnectionDetails = "Data Source=YOUR-SERVER;Initial Catalog=YourDatabaseName;Persist Security Info=True;User ID=YourUserName;Password=YourPassword";
public static void ChangeDatabaseSize(int databaseSize) {
const string preparedCommand = #"
ALTER DATABASE Accounting
MODIFY FILE
(NAME = 'Accounting', SIZE = #size)
";
using (var varConnection = SqlConnectOneTime(sqlDataConnectionDetails))
using (SqlCommand sqlWrite = new SqlCommand(preparedCommand, varConnection)) {
sqlWrite.Parameters.AddWithValue("#size", databaseSize);
sqlWrite.ExecuteNonQuery();
}
}
This is supporting method that makes it easy to establish connection everytime you want to write/read something to database.
public static SqlConnection SqlConnectOneTime(string varSqlConnectionDetails) {
SqlConnection sqlConnection = new SqlConnection(varSqlConnectionDetails);
try {
sqlConnection.Open();
} catch {
DialogResult result = MessageBox.Show(new Form {
TopMost = true
}, "No connection to database. Do you want to retry?", "No connection (000001)", MessageBoxButtons.YesNo, MessageBoxIcon.Stop);
if (result == DialogResult.No) {
if (Application.MessageLoop) {
// Use this since we are a WinForms app
Application.Exit();
} else {
// Use this since we are a console app
Environment.Exit(1);
}
} else {
sqlConnection = SqlConnectOneTime(varSqlConnectionDetails);
}
}
return sqlConnection;
}

Related

AccessViolationException thrown by OleDbConnection.Open()

I am getting a System.AccessViolationException error when trying to use the .Open() method on my OleDbConnection variable. But, confoundingly, it doesn't seem to happen when I run my code on a different computer.
My code is for a service that I want running on a server. It appears to work correctly when I run it on my personal computer, but it throws the AccessViolationException error when I try running it on the server.
Code Versions:
I am writing in C# using Visual Studios 2019 on Windows 10
OleDbConnection is from "Assembly System.Data, Version=4.0.0.0"
ADOX is from "Assembly Interop.ADOX, Version=2.8.0.0", System.Runtime.InteropServices
ADODB is from "Assembly Interop.ADODB, Version=2.8.0.0", System.Runtime.InteropServices
My code:
internal static bool CreateMDB(MySchemaClass schema, string filePath)
{
OleDbConnection conn = null;
bool status = true;
string connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}", filePath);
try
{
// Setup new file
catalog.Create(connectionString);
((ADODB.Connection)catalog.ActiveConnection).Close();
conn = new OleDbConnection(connectionString);
conn.Open(); // <-- Error occurs here
// Write to new file
WriteDataToFile(schema, conn);
}
catch (Exception ex)
{
status = false;
}
finally
{
if (conn != null)
conn.Close();
}
return status;
}
StackTrace:
The best lead I have found so far is this post, but I'm a bit hazy about how to proceed from that starting point.
To programmatically create an Access database do the following:
Add reference to Microsoft ADO Ext. 6.0 for DDL and Security
In VS menu, click Project
Select Add Reference
Click COM
Check Microsoft ADO Ext. 6.0 for DDL and Security
CreateAccessDatabase
public static string CreateAccessDatabase(string fullyQualifiedAccessFilename, string dbPassword = "")
{
string connectionString = String.Format(#"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = {0}", fullyQualifiedAccessFilename);
if (String.IsNullOrEmpty(fullyQualifiedAccessFilename))
{
throw new Exception("Error (CreateAccessDatabase) - Database filename is null or empty.");
}
if (!String.IsNullOrEmpty(dbPassword))
{
connectionString = String.Format(#"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = {0};Jet OLEDB:Database Password='{1}'", fullyQualifiedAccessFilename, dbPassword);
}
//create new instance
ADOX.Catalog cat = new ADOX.Catalog();
//create Access database
cat.Create(connectionString);
//close connection
cat.ActiveConnection.Close();
//release COM object
System.Runtime.InteropServices.Marshal.ReleaseComObject(cat);
GC.Collect();
cat = null;
return String.Format("Database created '{0}'", fullyQualifiedAccessFilename);
}
Usage:
string result = string.Empty;
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Access Database 2000-2003 (*.mdb)|*.mdb|Access Database 2007 (*.accdb)|*.accdb";
if (sfd.ShowDialog() == DialogResult.OK)
{
//create Access database
result = CreateAccessDatabase(sfd.FileName);
}
To programmatically create a table in an Access database:
Add using statement:
using System.Data.OleDb;
CreateTableProduct:
public static int CreateTableProduct(string fullyQualifiedAccessFilename, string dbPassword = "")
{
int result = 0;
string connectionString = String.Format(#"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = {0}", fullyQualifiedAccessFilename);
if (!String.IsNullOrEmpty(dbPassword))
{
connectionString = String.Format(#"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = {0};Jet OLEDB:Database Password='{1}'", fullyQualifiedAccessFilename, dbPassword);
}
string sqlText = string.Empty;
sqlText = "CREATE TABLE Product ";
sqlText += "(ID AUTOINCREMENT not null primary key,";
sqlText += " Name varchar(50) not null,";
sqlText += " Price currency, Quantity integer);";
using (OleDbConnection con = new OleDbConnection(connectionString))
{
//open connection
con.Open();
using (OleDbCommand sqlCmd = new OleDbCommand(sqlText, con))
{
//execute command
result = sqlCmd.ExecuteNonQuery();
}
}
return result;
}
Resources:
ADO Features for each Release
Which Access file format should I use?
CREATE TABLE statement (Microsoft Access SQL)
System.Data.OleDb Namespace
The underwhelming answer to the problem is that my server was lacking some of the files my personal computer had, and only needed the correct files installed.
The missing piece in this case was the Microsoft Access Database Engine 2016 Redistributable, which I ended up finding here. Running that executable on my server got the needed files and everything worked after that.

Fastest and right way to check if I have a connection to SQL Server in C#

I just want to check if I have a connection to a SQL Server for a sync my local database to it. And if I don't have to skip on it.
Also, it should work with wifi and cable connection.
When it connects with wifi some time my network is off but the method
System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()
returns true so this method does not work well for me.
I also try just to check the connection to my SQL Server like that
public bool TestServerConnection()
{
using (SqlConnection openCon = new SqlConnection(connectionString))
{
try
{
string saveStaff = "select 1";
SqlCommand command = new SqlCommand(saveStaff, openCon);
command.CommandTimeout = 1;
openCon.Open();
if (openCon.State == ConnectionState.Open)
{
return true;
}
else
{
return false;
}
}
catch (Exception)
{
return false;
}
}
}
With this connection string
Data Source=CV-TED-SQL1;Initial Catalog = PulserDb; Integrated Security=true;MultipleActiveResultSets=True;
But when I have no connection for example when I change Data Source=CV-TED-SQL1; to Data Source=CV-TED-SQL11;, the openCon.Open(); takes about 10 seconds..
That just too long..
There is any fastest way to do that?
I can't change my connection string, maybe I can change it only for my method and change it back when this method end
Thanks for the help.
EDITING A NEW TEST METHOD
public bool TestServerConnection()
{
Stopwatch stopwatch = Stopwatch.StartNew();
string tempCS = connectionString;
SqlConnectionStringBuilder scb = new SqlConnectionStringBuilder(tempCS);
scb.ConnectTimeout = 1;
using (SqlConnection openCon = new SqlConnection(scb.ToString()))
{
try {
string saveStaff = "select 1";
SqlCommand command = new SqlCommand(saveStaff, openCon)
{
CommandTimeout = 1
};
openCon.Open();
if (openCon.State == ConnectionState.Open)
{
stopwatch.Stop();
return true;
}
else
{
stopwatch.Stop();
return false;
}
}
catch (Exception)
{
stopwatch.Stop();
return false;
}
}
}
If you cannot change the connection string to add a Connect Timeout key then you can change the connection string at runtime with little effort using the SqlConnectionStringBuilder as shown below
SqlConnectionStringBuilder scb = new SqlConnectionStringBuilder(connectionString);
scb.ConnectTimeout = 5; // 5 seconds wait 0 = Infinite (better avoid)
connectionString = scb.ToString();
Console.WriteLine(connectionString);
using(SqlConnection cnn = new SqlConnection(connectionString)
{
}

cannot access database from multiple unit tests

I had the connection string and a bunch of my unit tests using it in order to test the logic of some class which was applying some CRUD operations to it. So I was passing it as a private constant field in test class and sharing it to my tests. Everything worked perfectly fine!
But then I realized I have to do it as integration testing. So I've decided to use static helper class to create database via session for me tests to work with it and then drop.
The class is the following:
public static class LocalDB
{
public const string DB_DIRECTORY = "Data";
public static string GetLocalDB(string dbName, bool deleteIfExists = false)
{
try
{
var outputFolder = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), DB_DIRECTORY);
var mdfFilename = dbName + ".mdf";
var dbFileName = Path.Combine(outputFolder, mdfFilename);
var logFileName = Path.Combine(outputFolder, $"{dbName}_log.ldf");
if (!Directory.Exists(outputFolder))
{
Directory.CreateDirectory(outputFolder);
}
if (File.Exists(dbFileName) && deleteIfExists)
{
if (File.Exists(logFileName)) File.Delete(logFileName);
File.Delete(dbFileName);
CreateDatabase(dbName, dbFileName);
}
else if (!File.Exists(dbFileName))
{
CreateDatabase(dbName, dbFileName);
}
var connectionString = string.Format(#"Data Source=(LocalDB)\v11.0;AttachDBFileName={1};Initial Catalog={0};Integrated Security=True;", dbName, dbFileName);
CreateTable(connectionString, "Cpa", dbName);
return connectionString;
}
catch(Exception ex)
{
throw;
}
}
public static bool CreateDatabase(string dbName, string dbFileName)
{
try
{
var connectionString = #"Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var cmd = connection.CreateCommand();
DetachDatabase(dbName);
cmd.CommandText = string.Format("CREATE DATABASE {0} ON (NAME = N'{0}', FILENAME = '{1}')", dbName, dbFileName);
cmd.ExecuteNonQuery();
cmd.Dispose();
}
return File.Exists(dbFileName);
}
catch
{
throw;
}
}
public static bool DetachDatabase(string dbName)
{
try
{
var connectionString = $#"Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = $"exec sp_detach_db '{dbName}'";
cmd.ExecuteNonQuery();
cmd.Dispose();
return true;
}
}
catch(Exception ex)
{
return false;
}
}
public static bool CreateTable(string connectionString, string tableName, string dbName)
{
connectionString = connectionString.Replace("master", dbName);
try
{
using (var connection = new SqlConnection(connectionString))
{
var createTableQuery = $#"CREATE TABLE {tableName}(
CrmId nvarchar(50) NOT NULL,
Service nvarchar(25) NOT NULL,
RecurringReference nvarchar(50),
ExpiryDate datetime,
CardNumber nvarchar(50),
Enabled bit,
Brand nvarchar(50),
CpaType nvarchar(50),
Channel nvarchar(50)
);";
var command = new SqlCommand(createTableQuery, connection);
connection.Open();
var reader = command.ExecuteReader();
reader.Dispose();
return true;
}
}
catch (Exception ex)
{
return false;
}
}
}
I was calling it's GetLocalDB method in my test class' ctor amd initializing field.
After that I've got the following error "the process cannot access the file blah log.ldf because it is used by another process"
!!! All the tests were using the same connection string, I have no idea what's gone wrong. It can't be the unit tests failure for all I've changed is connection string (was for already existent db -> changed to temporary local (LocalDb class))
Thanks!
I also used localDb for testing in my web application and had a similar issue. This issue can sometime happen if while debugging you stopped in between or some test ran into any exception and disposing of localdb did not happen properly. If that happens then next time when you start running test it wont create the db(inspite of the check ifdbexists) and run into some exception like you mentioned. To check I added a different name every time we ran a set of tests so that db gets created on start of running test and drops after executing all the tests.As its not ideal to give different name every time , try disposing the localdb in a finally block to make sure it happens even in case of exception

SQL Server connections in ASP.NET application [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have created a web application with asp.net, roughly 100 users are using it.
However from time to time people are getting the error message that the connection is still open. Indicating that it was not closed properly.
It appears on random places, not one specific place and no other errors before it.
I know that when I have a bug in the application and it crashes without me gracefully dealing with the error the connection remains open as well and basically everyone will crash because of it. This made me think that everyone uses the same connection object, is it possible that 2 users might have the perfect timing and invoke a function using a DB connection at the same time causing the error? Is there a way to make sure everyone uses their own connection objects, like put it in their session or something?
I hope you can understand what I mean, I don't think posting any of my code will help since it happens on random places within my project.
They are connection to a SQL Server using System.Data.SqlClient.
Find below the function which generates the error. This function is called by the Page_Load, nothing is before it.
public static SqlConnection conn = new SqlConnection("Data Source=Server00\\SQLEXPRESS;Initial Catalog=r2;Integrated Security=true;Connect Timeout=0");
private void populateGameDrop()
{
try
{
conn.Open();
drop_game.Items.Clear();
SqlCommand cmd = conn.CreateCommand();
Access ac = (Access)Session["Access"];
cmd.CommandText = "Select * from dbo.Games where " + ac.GameQuery;
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
drop_game.Items.Add(new ListItem(r["name"].ToString(), r["Abbr"].ToString()));
}
conn.Close();
}
catch (Exception exc)
{
conn.Close();
Log.Error(exc.ToString());
Session["Error"] = exc.ToString();
Response.Redirect("~/YouBrokeIt.aspx");
}
populateServers();
SetSplitScreen();
}
Don't try to share SqlConnection objects.
Try this instead:
private static string connString = "Data Source=Server00\\SQLEXPRESS;Initial Catalog=r2;Integrated Security=true;Connect Timeout=0";
private void populateGameDrop()
{
try
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
drop_game.Items.Clear();
using (var cmd = conn.CreateCommand())
{
Access ac = (Access)Session["Access"];
//TODO
//TODO - Introduce parameters to avoid SQL Injection risk
//TODO
cmd.CommandText = "Select name,Abbr from dbo.Games where " + ac.GameQuery;
using(SqlDataReader r = cmd.ExecuteReader())
{
while (r.Read())
{
drop_game.Items.Add(new ListItem(r["name"].ToString(),
r["Abbr"].ToString()));
}
}
}
}
}
catch (Exception exc)
{
Log.Error(exc.ToString());
Session["Error"] = exc.ToString();
Response.Redirect("~/YouBrokeIt.aspx");
}
populateServers();
SetSplitScreen();
}
Behind the scenes, .NET uses a concept called connection pooling so that the actual number of real connections to SQL Server are minimized. But SqlConnection objects aren't designed to be shared by multiple threads.
Don't place your database code directly in your ASPX pages. Creating an extra layer (i.e. DAL) allows you to test the DB methods without using the page.
Try something like this.
//Don't embed database logic directly in the aspx files
public class GamesProvider
{
//Put the ConnectionString in you configuration file
private string ConnectionString
{
get { return ConfigurationManager.ConnectionStrings["GameDB"].ConnectionString; }
}
public IEnumerable<Game> LoadGames(string x, string y)
{
var games = new List<Game>();
const string queryString = "select name, Abbr from dbo.Games where x = #x and y = #y";
using (var connection = new SqlConnection(ConnectionString))
using (var command = new SqlCommand(queryString, connection))
{
command.Parameters.AddWithValue("#x", x);
command.Parameters.AddWithValue("#y", y);
using (var dateReader = command.ExecuteReader())
{
while (dateReader.Read())
{
var game = new Game
{
Name = dateReader["name"].ToString(),
Abbr = dateReader["Abbr"].ToString(),
};
games.Add(game);
}
}
}
return games;
}
}
//Use types
public class Game
{
public string Name { get; set; }
public string Abbr { get; set; }
}
Your SQL connections shouldn't be static, use the following to create them
var connectionString = "YOUR CONNECTION STRING";
var queryString = "SQL QUERY";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryString, connection))
using (SqlDataReader dateReader = command.ExecuteReader()) {
}
VERY IMPORTANT
You should use parameterised SQL your code is open to SQL injection attacks.
please see Parameterize SQL query

Why are there connections open to my databases?

I have a program that stores user projects as databases. Naturally, the program should allow the user to create and delete the databases as they need to. When the program boots up, it looks for all the databases in a specific SQLServer instance that have the structure the program is expecting. These database are then loaded into a listbox so the user can pick one to open as a project to work on.
When I try to delete a database from the program, I always get an SQL error saying that the database is currently open and the operation fails. I've determined that the code that checks for the databases to load is causing the problem. I'm not sure why though, because I'm quite sure that all the connections are being properly closed.
Here are all the relevant functions. After calling BuildProjectList, running "DROP DATABASE database_name" from ExecuteSQL fails with the message: "Cannot drop database because it is currently in use". I'm using SQLServer 2005.
private SqlConnection databaseConnection;
private string connectionString;
private ArrayList databases;
public ArrayList BuildProjectList()
{
//databases is an ArrayList of all the databases in an instance
if (databases.Count <= 0)
{
return null;
}
ArrayList databaseNames = new ArrayList();
for (int i = 0; i < databases.Count; i++)
{
string db = databases[i].ToString();
connectionString = "Server=localhost\\SQLExpress;Trusted_Connection=True;Database=" + db + ";";
//Check if the database has the table required for the project
string sql = "select * from TableExpectedToExist";
if (ExecuteSQL(sql)) {
databaseNames.Add(db);
}
}
return databaseNames;
}
private bool ExecuteSQL(string sql)
{
bool success = false;
openConnection();
SqlCommand cmd = new SqlCommand(sql, databaseConnection);
try
{
cmd.ExecuteNonQuery();
success = true;
}
catch (SqlException ae)
{
MessageBox.Show(ae.Message.ToString());
}
closeConnection();
return success;
}
public void openConnection()
{
databaseConnection = new SqlConnection(connectionString);
try
{
databaseConnection.Open();
}
catch(Exception e)
{
MessageBox.Show(e.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void closeConnection()
{
if (databaseConnection != null)
{
try
{
databaseConnection.Close();
}
catch (Exception e)
{
MessageBox.Show(e.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
The SqlConnection class polls the actual database connection. If you close the SqlConnection, the connection is returned to the Connection pool. To prevent this behaviour, set SqlConnection.Pooling = false;.
edit
John seems to be more to the point here. But you might have to keep polling in mind as well.
Two comments. First off, you should use a using statement and your could will be much cleaner.
More on topic, you are connecting to the database when you are trying to drop it! Connect to the master database instead.

Categories