Copy entire SQL Database via C#'s SqlConnection - c#

I have two connection strings, the first is to an existing database, and the second is to a different SQL Server. I need to copy the entire first database to the second one. This includes creating all the tables, constraints, and keys. I want to use the SqlConnection object and do not have access to a hard drive.
EDIT 1:
I can create the db (code below) but I can't figure out how to programmatically set up the tables and then populate them. What is the best way to approach this?
public void Copy()
{
var connectionForExisting = "REDACTED";
var connectionForNew = "REDACTED";
var targetDbName = "REDACTED";
var source = new SqlConnection(connectionForExisting);
var target = new SqlConnection(connectionForNew);
try
{
source.Open();
}
catch (Exception e)
{
source.Close();
return;
}
try
{
target.Open();
}
catch (Exception e)
{
source.Close();
target.Close();
return;
}
var myCommand = new SqlCommand(String.Format(CreateNewDatabaseScript, targetDbName), target);
try
{
myCommand.ExecuteNonQuery();
}
catch (Exception e)
{
source.Close();
target.Close();
return;
}
}

Related

Splitting data access and catching data to form

In my project I'm trying to write code that will be nice to understand.
I currently split my data access functions in a seperate class.
What I'm trying to achieve however, is to catch the errors back to my form. I am not getting this currently and I was wondering why.
In my form I have the following code:
private void btn_Save_ItemClick(object sender, ItemClickEventArgs e)
{
if (dal.updatePerson(ObjectAfterSaving))
{
MessageBox.Show("Updated!");
}
else
{
MessageBox.Show("error");
};
}
In my dal object (derived from the DataAccess_Person class), I have the following method:
public bool updatePerson(Person p)
{
conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Database"].ConnectionString);
SqlCommand command = new SqlCommand(#"UPDATE Person
SET PersonName = #PersonName
WHERE PersonID = #PersonID", conn);
command.Parameters.Add("#PersonName", SqlDbType.VarChar).Value = p.Name
{
try
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
int a = command.ExecuteNonQuery();
conn.Close();
if (a > 0)
{
return true;
}
else
{
return false;
}
}
catch (SqlException ex)
{
ex.ToString();
return false;
}
}
}
My question is: let's say if my method falls in the catch. Will my front end (form) show it (Sql Exception for example) ? Or will i just get 'error' ? And If I will just get error, how I can improve my code to show the Exception instead of error?
A simple way is to remove the try catch from your DAL and add it to the form. For example:
private void btn_Save_ItemClick(object sender, ItemClickEventArgs e)
{
var result = "Success";
try
{
dal.updatePerson(ObjectAfterSaving);
}
catch (SqlException sqlEx)
{
result = sqlEx.Message;
}
catch (Exception ex)
{
result = ex.Message;
}
MessageBox.Show(result);
}
Just note that there's a lot of ways you can do this. My preference is to not include DAL specific exception types in my UI. Instead I may return a custom result type that has an errorcode and message and let my UI display that or generate a custom message based on the error code.
You‘ll just get „error“ in case of a SqlException. All other exceptions will crash your program if you don‘t have a global exception handler. If you want to show the error message you could introduce an out variable for the error message:
bool successful = MyMethod(out string errorMessage)
if (!successful)
{
MessageBox.Show(errorMessage);
}
public bool MyMethod(out string errorMessage)
{
errorMessage = "";
try
{
// do some stuff
return true;
}
catch(Exception ex)
{
errorMessage = ex.Message;
return false;
}
}

Best way to handle error catching

I am creating an app which does some SQL server config, which part of a bigger system
There is a config table in the database of the system as follows:
CREATE TABLE Config
(
ConfigItem NVARCHAR(255) PRIMARY KEY NOT NULL,
ConfigValue NVARCHAR(255) NOT NULL
)
INSERT INTO Config
VALUES
('LinkedServerName','MYLINKEDSERVER'),
('DatabaseName','APPLICATIONDATABASE')
My app is a Windows form with two textboxes and a button. The form also has an initially blank label which is used to display error messages to the user.
In the first text box, the value for the linked server name is shown, in the second, the value for the database is shown. Both are shown on form load.
On clicking the submit button, the two values are updated in the database based on what is in the text boxes.
I have the following code to populate the two textboxes with current values at form load:
private void Form1_Load(object sender, EventArgs e)
{
// populate the textboxes
txtLinkedServer.Text = GetConfigValue("LinkedServerName");
txtDatabase.Text = GetConfigValue("DatabaseName");
}
private string GetConfigValue(string ConfigItem)
{
// get the value for the given config item from the database
using (SqlConnection conn = new SqlConnection(connectionString))
{
DataTable dt = new DataTable();
SqlCommand com = new SqlCommand();
com.CommandText = "SELECT ConfigValue FROM Config WHERE ConfigItem = #ConfigItem";
com.Parameters.AddWithValue("ConfigItem", ConfigItem);
com.Connection = conn;
try
{
conn.Open();
dt.Load(com.ExecuteReader());
if (dt.Rows.Count == 0)
{
return "Error retrieving " + ConfigItem + " name from config table";
}
else
{
return dt.Rows[0]["ConfigValue"].ToString();
}
}
catch
{
return "Error in GetConfigValueMethod when retrieving " + ConfigItem;
}
finally
{
conn.Close();
}
}
}
If there is a problem with retrieving the config data (caught by the catch block in GetConfigValue) I want the label to show the string returned from GetConfigValue.
What is the best / neatest way to do this? I was thinking
private void Form1_Load(object sender, EventArgs e)
{
string message;
// populate the textboxes
try
{
message = GetConfigValue("LinkedServerName");
txtLinkedServer.Text = message
}
catch
{
lblFeedback.Text = message;
}
// do the same for the database here
}
however, I cannot do that as I get
Use of unassigned local variable 'Message'
Or am i best to change the GetConfigValue method so that it throws it's own exception in the catch block rather than returning a string and catching that in the Load method as follows;
private string GetConfigValue(string ConfigItem)
{
// get the value for the given config item from the database
using (SqlConnection conn = new SqlConnection(connectionString))
{
// same code here
try
{
// same code here
}
catch
{
Throw new Exception ("Error in GetConfigValueMethod when retrieving " + ConfigItem);
}
finally
{
conn.Close();
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
// populate the textboxes
try
{
txtLinkedServer.Text = GetConfigValue("LinkedServerName");
}
catch (Exception e)
{
lblFeedback.Text = e.Message;
}
// do the same for the database here
}
Or some other way completely?
Looking at your second example, if that's the result you want, then it looks like you just need to replace
catch
{
lblFeedback.Text = message;
}
in your first example with
catch (Exception e)
{
lblFeedback.Text = e.Message;
}
from your second example.
As error message says you tried to use unassigned variable 'message' and because of that you were getting that error.
Try this:
private void Form1_Load(object sender, EventArgs e)
{
string message = String.Empty;
// populate the textboxes
try
{
message = GetConfigValue("LinkedServerName");
txtLinkedServer.Text = message
}
catch (Exception ex)
{
if (!String.IsNullOrEmpty(message))
lblFeedback.Text = message;
else
lblFeedback.Text = ex.Message;
}
// do the same for the database here
}

How to handle SQL Exception for Logon failure

I have a windows form that presents a combo box for the user to select a geographical region and then sets SQL Connections based on the selection and executes a SQL Command. There is always a good chance the user doesn't have access to the SQL Server. I set up a try/catch and display the error message to the user but don't really want to break and I'm new to VS C# and am asking for guidance on how to pass control to a point the user can adjust by making a different selection.
Would it be reasonable to pass execution back to the form load? If yes, how do I do that? If no, how should it be handled?
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex > 0)
{
List<String> distinctTableList = AttributeMap.DistinctTablesList(comboBox1.SelectedItem.ToString());
lbTableNames.DataSource = distinctTableList;
}
}
public static List<String> DistinctTablesList(String environment)
{
List<String> tables = new List<string>();
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
AppSettingsSection appSettingSection = (AppSettingsSection)config.GetSection("cbSettings");
SqlConnection sqlcon = new SqlConnection(appSettingSection.Settings[environment].Value);
using (sqlcon)
{
StringBuilder errorMessages = new StringBuilder();
using (sqlcon)
{
try
{
sqlcon.Open();
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
}
public partial class frmClassBuilder : Form
{
private List<AttributeMap> attributeMapList;
private CacheClassFactory cacheFactory;
public frmClassBuilder()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<String> environmentList = AttributeMap.EnvironmentList();
comboBox1.DataSource = environmentList;
}
=============================================================
using (sqlcon)
{
try
{
sqlcon.Open();
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
}
I have used the following approach in one of enterprise desktop clients and it is still used.
Assuming you have combobox_SelectedIndexChanged() method, it should look like this:
public void combobox_SelectedIndexChanged()
{
string selectedCountry = "country"; //build actual connection string as you do now.
string connectionString = string.Format("Data Source={0};Initial Catalog=Detrack;Integrated Security=True;", selectedCountry);
var sqlCon = new SqlConnection(connectionString);
using (sqlCon)
{
// Disable some controls
try
{
sqlCon.Open();
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
// Disable "OK"/"Next" button
return;
}
finally
{
///Enable controls
}
sqlCon.Close();
// "OK"/"Next" button
}
}
In this method, you check if connection can be opened,
If it can't:
display error message
disable controls that allow user to continue interaction, until correct selection is made
If it can, just close connection and go forth to the next part of the code, where you actually use the connection.
You'll also require some sort of "Checking connection" message displayed to the user and blocking his interaction while connection is being checked.

How can I update Username and password in aspnet_Users table and other table was created by me tbl_users simultaneously?

I am Making a Web project and maintaining role management in this application. When I had been created web project then I defined role management in this application. When I create an user using createUser() function data stores in aspnet_Users,aspnet_Membership and other table that one has been created by me (tbl_users),stores all user information including some info of aspnet_Users,aspnet_Membership table. I am able to create data in these tables simultaneously but now I want to update and delete data in these tables simultaneously,how can it be possible please??..let me know.
Here is My code
protected void btn_signup_Click(object sender, EventArgs e)
{
try
{
// Create new user.
objuser.email=txt_email.Text;
objuser.password=txt_password.Text;
objuser.username = TextBox1.Text;
if (Membership.RequiresQuestionAndAnswer)
{
MembershipUser newUser =
Membership.CreateUser(objuser.email,objuser.password,
objuser.username);
}
else
{
MembershipUser newUser = Membership.CreateUser(
objuser.email,
objuser.password,
objuser.username);
int i = BusinessUser.BusinessRegisterUser(objuser);
if (i > 0)
{
Session["user_authenticate"] = "Verified";
Session["user_email"] = objuser.email;
Label1.Text = Session["user_email"].ToString();
login1.Style.Add("display", "none");
logout.Visible = true;
Response.Redirect("user_registration.aspx");
}
}
show_menu();
//Response.Redirect("login.aspx");
}
catch (MembershipCreateUserException ex)
{
WarningModal.Show();
lblWarning.Text = GetErrorMessage(ex.StatusCode);
pnlIssues.Visible = true;
}
catch (HttpException ex)
{
WarningModal.Show();
lblWarning.Text= ex.Message;
}
}
protected void loginUser_Authenticate(object sender, AuthenticateEventArgs e)
{
try
{
if (Membership.ValidateUser(loginUser.UserName, loginUser.Password))
{
Session["user_authenticate"] = "Verified";
e.Authenticated = true;
Session["user_email"] = loginUser.UserName;
objuser.email = Session["user_email"].ToString();
Label1.Text = Session["user_email"].ToString();
login1.Style.Add("display", "none");
logout.Visible = true;
}
else
{
e.Authenticated = false;
}
}
catch (Exception ex)
{
}
}
You could always put a trigger on the aspnet_membership table that cascades the update and delete actions to the tbl_user table.
http://technet.microsoft.com/en-us/library/ms189799.aspx

How should I properly be retrieving database records via SqlConnection?

I'm sure this question has been asked many times, and I dug through a few of the similar ones but couldn't find one that really flushed it out as much as I'd have liked.
I have an application that uses a database helper class to connect and retrieve records from a database. I was considering rewriting it and wanted to know what the best way to do it would be.
Here is roughly how it's set up now (Note: This is already in place, and there are thousands of lines of this stuff).
DatabaseHelper.CS
private SqlConnection conn;
public DatabaseHelper()
{
// Create database connection
conn = new System.Data.SqlClient.SqlConnection();
SqlConnectionStringBuilder connection = new SqlConnectionStringBuilder();
connection.ConnectTimeout = 150; // Microsft fix for timeout error (known bug)
connection.MinPoolSize = 20; // Microsft fix for timeout error (known bug)
connection.DataSource = Properties.Settings.Default.DBString;
connection.InitialCatalog = Properties.Settings.Default.DBInitCatalog;
connection.IntegratedSecurity = true;
if (conn.State != ConnectionState.Connecting)
{
conn.ConnectionString = connection.ConnectionString;
}
}
public bool Open()
{
if (this.IsOpen()) // IsOpen is just a method that checks connectionstate.
{ return true; }
else
{
try
{
conn.Open();
return true;
}
catch (System.Data.SqlClient.SqlException ex)
{
// omitted for post
}
}
return false;
}
public bool Close()
{
if (!this.IsOpen())
{ return true; }
try
{
conn.Close();
return true;
}
catch (System.Data.SqlClient.SqlException ex)
{
// omitted for post
}
return false;
}
public List<string> GetTeamLeaders(string team)
{
List<string> leaders = new List<string>();
string query = "Select Leader FROM Teams WHERE Team = #team_vc";
try
{
using (SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add("#team_vc", SqlDbType.NVarChar).Value = team;
using (SqlDataReader sdr = cmd.ExecuteReader())
{
int column = sdr.GetOrdinal("Leader");
while (sdr.Read())
{
leaders.Add(sdr[column].ToString());
}
}
}
}
catch (Exception ex)
{
// omitted for post
}
return leaders;
}
private string GetTeamAbbrev(string team)
{
string abbrev= "";
string query = "SELECT Abbrev FROM Teams where Team = #team_vc";
using (SqlCommand cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add("#team_vc", SqlDbType.NVarChar).Value = team;
try
{
abbrev= Convert.ToString(cmd.ExecuteScalar());
}
catch (Exception ex)
{
// omitted for post
}
}
return (string.IsNullOrEmpty(location)) ? "None" : abbrev;
}
MainApp.CS
private DatabaseHelper dbHelper;
public MainApp()
{
InitializeComponent();
dbHelper= new DatabaseHelper(); // Instantiate database controller
}
private void someButton_Click(object sender, EventArgs e)
{
List<string> teamLeaders = new List<string>();
if (dbHelper.Open())
{
teamLeaders = dbConn.GetTeamLeaders(textboxTeam.Text);
dbHelper.Close();
}
else
{
return;
}
// all the code to use results
}
private void someOtherButton_Click(object sender, EventArgs e)
{
List abbreviation = string.Empty;
if (dbHelper.Open())
{
abbreviation = dbConn.GetTeamLeaders(textboxTeam.Text);
dbHelper.Close();
}
else
{
return;
}
// all the code to use results
}
Now I'm sure there are some very serious issues with how this is setup, but for me my biggest complaints are always having to open and close the connection.
My first move was to just move the open and close inside the DatabaseHelper methods, so each method (i.e. GetTeamLeaders) would call open and close in itself. But the problem was if it did actually fail to open it was really hard to feed it back up to the main program, which would try to run with whatever value the variable contained when it was made. I was thinking I would almost need an "out" bool that would tag along to see if the query completed, and could check make and check that anytime I used I needed to get something from the database, but I'm sure that has issues to.
Another big problem with this approach is anytime I want to make a call from another form, I have to either make another instance of the helper on that form, or pass a reference to the main one. (Currently my way around this is to retrieve all the information I would need beforehand in the MainApp and then just pass that to the new form). I'm not sure if when I rewrite this there's a good static way to set it up so that I can call it from anywhere.
So is there anything here worth keeping or does it all need to be stripped down and built back from scratch?

Categories

Resources