executereader commandtext property has not been initialized c# - c#

this is a piece of code which is showing exception. It take sql query entered in text from textbox on the Window form (testform) and display the result in excel sheet. how can i take value in string to so that it dont show exception and that sql1 is textbox name is empty function in Testform.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.IO;
using System.Windows.Forms;
using Exceloutput_Application;
public class ProcessDataset
{
public ProcessDataset()
{
}
public static DataTable ReadTable()
{
TestForm t = new TestForm();
var returnValue = new DataTable();
var conn = new SqlConnection(ConnectionString._connectionString);
string st = t.sql1.Text;
try
{
conn.Open();
var command = new SqlCommand(st, conn);
using (var adapter = new SqlDataAdapter(command))
{
adapter.Fill(returnValue);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
finally
{
if (conn.State == ConnectionState.Open)
conn.Close();
}
return returnValue;
}
}

You either assume that instantiating (new) a Form magically shows it or gets a reference to an existing open form. None of those assumptions is true.
To show a form to the user you either call Application.Run for your first form (the main form of your application) or Show
or ShowDialog on a instance you created.
Let me add comments to the first few lines of your ReadTable method:
TestForm t = new TestForm(); // this ONLY creates a NEW form in memory
// if you were looking at a TestForm already t holds a new form
// and not the one you're looking at.
var returnValue = new DataTable();
var conn = new SqlConnection(ConnectionString._connectionString);
// the form is not shown to the user at this point
// and never will be because YOU didn't tell it to Show
// The textbox is empty
string st = t.sql1.Text;
// st will be an empty string here
With that explained let's see possible solutions. You might be tempted to add
t.Show();
directly after you created the TestForm. That does show the form but Show is non-blocking. Which means it will continue immediately with the rest of the code still leading to an empty result in st.
t.ShowDialog();
will enable you to see the form and fill in any values. ShowDialog will block until the users closes the form or you have a button that calls Close or Hide in the click event.
Based on the sparse information you provided I assume you already have TestForm open, with a button on it that calls ReadTable. If you change ReadTable to accept a the sql string, you don't have to juggle with the forms.
Something like this will do:
public class ProcessDataset
{
// Takes a Sql string
public static DataTable ReadTable(string sql)
{
var returnValue = new DataTable();
// checks if there is a sql string provided
if (!String.IsNullOrEmpty(sql))
{
var conn = new SqlConnection(ConnectionString._connectionString);
conn.Open();
var command = new SqlCommand(sql, conn);
// rest of code
}
else
{
// show message to user
MessageBox.Show(" no sql command ");
}
return returnValue;
}
}
And you will call it from your click event like so:
private void button2_Click(object sender, EventArgs e)
{
var resultset = ProcessDataset.ReadTable(sql1.Text);
}
tl;dr There is not much wrong with your SqlCommand code. You simply failed in getting the correct reference to your Textbox that contains some sql statement. Calling sqlcommand with an empty string raises the exception you are seeing.

Related

Try statement not executing - goes straight to catch

I am setting up a winform that takes the first name, last name, and student ID of a student into an sql database named college, and performs a stored procedure which searches for that student, then displays the results in a DataGridView when the search button is pressed. Whenever I press the search button I get the following error
"A first chance exception of type 'System.TypeInitializationException' occurred in Search2.exe".
My program is skipping over the Try block shown, and going to the Catch statement. Can anyone tell me why this is?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Search2
{
public partial class frmSearch : Form
{
public frmSearch()
{
InitializeComponent();
}
private void btnSearch_Click(object sender, EventArgs e)
{
string studid, fname, lname;
try
{
// get the values
fname = txtFname.Text.Trim();
lname = TxtLname.Text.Trim();
studid = txtStudentID.Text.Trim();
//instantiate datatier
Class1 astudent = new Class1();
DataSet ds = new DataSet();
ds = astudent.GetStudents(studid, fname, lname);
// populate the datagrid with dataset
dgvStudents.DataSource = ds.Tables[0];
}
catch (Exception ex)
{
}
}
private void frmSearch_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'collegeDataSet.STUDENT' table. You can move, or remove it, as needed.
//this.sTUDENTTableAdapter.Fill(this.collegeDataSet.STUDENT);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Data.SqlClient;
using System.Globalization;
namespace Search2
{
class Class1: frmSearch
{
static String connString = ConfigurationManager.ConnectionStrings["Data Source=EVEDELL17;Initial Catalog=College;Integrated Security=True"].ConnectionString;
static SqlConnection myConn = new SqlConnection(connString);
static System.Data.SqlClient.SqlCommand cmdString = new System.Data.SqlClient.SqlCommand();
public DataSet GetStudents(string studid, string fname, string lname)
{
try
{
// Open Connection
myConn.Open();
//clear command argument
cmdString.Parameters.Clear();
//command
cmdString.Connection = myConn;
cmdString.CommandType = CommandType.StoredProcedure;
cmdString.CommandTimeout = 1500;
cmdString.CommandText = "SearchStudent";
// define input parameter
cmdString.Parameters.Add("#fname", SqlDbType.VarChar, 1).Value = fname;
cmdString.Parameters.Add("#lname", SqlDbType.VarChar, 25).Value = lname;
// adapter and daraset
SqlDataAdapter aAdapter = new SqlDataAdapter();
aAdapter.SelectCommand = cmdString;
DataSet aDataSet = new DataSet();
// fill adapter
aAdapter.Fill(aDataSet);
//return Dataset
return aDataSet;
}
catch (Exception ex)
{
throw new ArgumentException(ex.Message);
}
finally
{
myConn.Close();
}
}
}
}
Judging by the exception type--TypeInitializationException--I suspect the problem is with the static field initializers:
static String connString = ConfigurationManager.ConnectionStrings["Data Source=EVEDELL17;Initial Catalog=College;Integrated Security=True"].ConnectionString;
static SqlConnection myConn = new SqlConnection(connString);
static System.Data.SqlClient.SqlCommand cmdString = new System.Data.SqlClient.SqlCommand();
Those initializers will run the first time their containing class (Class1) is "touched" by the runtime. Because they aren't in a method, it's hard for the compiler to give a helpful stack trace when they fail. Try replacing the inline initializers with a static constructor:
static String connString;
static SqlConnection myConn;
static System.Data.SqlClient.SqlCommand cmdString;
static Class1() {
connString = ConfigurationManager.ConnectionStrings["Data Source=EVEDELL17;Initial Catalog=College;Integrated Security=True"].ConnectionString;
myConn = new SqlConnection(connString);
cmdString = new System.Data.SqlClient.SqlCommand();
}
I think you'll get a better error message that way. You can also set a breakpoint in the constructor to see exactly what happens during initialization.
Read more here: https://learn.microsoft.com/en-us/dotnet/api/system.typeinitializationexception?view=netframework-4.8#Static
Xander got the answer I think: Something goes "bump" when initializing those static fields. And static/type constructors are notoriously poor at communicating exceptions:
https://learn.microsoft.com/en-us/dotnet/api/system.typeinitializationexception
The underlying problem however, is one of pattern. And there are several issues. However you can often fudge these parts for simple learning examples.
Disposeable
SqlConnectons is Disposeable, as it contains some unmanaged resources. Always dispose of disposeables. My personal rule is:
never split the Creation and Disposing of a Disposeable resource. Create, Use, Dispose. All in the same piece of code - ideally using a using statement/block.
The rare exception is if you wrap around something disposeable that you can not Dispose (or even just might ocassionally). In that case implent the Dispose pattern yourself, with the sole purpose of relaying the Dispose() call. (Approxmialtey 95% of all classes are only Disposeable because of this).
Avoid Globals/Static
Static variables are global variables. And quicklly after inventing those, we realized that using either was a terrible idea 90% of the time. Particular for exchanging/sharing data.
While I go even a bit further, never have a field that is static and can be written. constant and readonly (runtime constants) should be the only statics you ever use. If you can not make it that, do not make it static. Stuff like connection strings are way up on that rule. If you can not tag it like that, do not make it a static to begin with.
At tops I make a class, struct or tupple. And assign a instance of it to a static readonly/constant variable. Stuff like connection strings are either a instance variable, or handed in on each call of a function like GetStudents. Indeed, Class1 looks a lot like a DB access abstraction. And those in particular fall under the "do not make static" rule.

How to read a CSV file into an SQL table

I'm trying to read a CSV file into a table that I have created in Visual Studio. I want to validate the values in the file to see if they are correct, if all the values pass the checks, it will go into the table. If any values are not correct, an error report will be created using a JSON file.
I have already got some test data ready but I'm not sure how to separate the correct data from the incorrect data after the checker are complete.
public partial class NHSBatchChecker : Form
{
public NHSBatchChecker()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = #"C:\Users\wy6282\Desktop\VS\NHSBATCHCHECKER\Test.txt"; // Start in C: drive
openFileDialog1.Title = "Browse Text Files";
openFileDialog1.RestoreDirectory = true;
openFileDialog1.DefaultExt = "txt"; // Extension of file is txt only
openFileDialog1.Filter = "Text|*.txt||*.*"; //Only text files allowed
openFileDialog1.CheckFileExists = true; // Error message if file does not exist
openFileDialog1.CheckPathExists = true; // Error message if invalid file path
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string connectionstring;
SqlConnection cnn;
connectionstring = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\wy6282\Desktop\VS\NHSBATCHCHECKER\nhsBatchChecker\Results.mdf;Integrated Security=True";
cnn = new SqlConnection(connectionstring);
cnn.Open();
SqlCommand command;
SqlDataAdapter adaper = new SqlDataAdapter();
string sql = "";
sql = "Insert into Results(NHS Number, Date of Birth, First Name, Last Name, Title, Gender) values()";
command = new SqlCommand(sql, cnn);
adaper.InsertCommand = new SqlCommand(sql, cnn);
adaper.InsertCommand.ExecuteNonQuery();
command.Dispose();
cnn.Close();
How do I add my valid records into the sql table?
you're trying to do too much in one go.
rule number 1: always split your problem into manageable junks:
read data from CSV.
filter incorrect data
save filtered data to database.
Now you have 3 distinct pieces of work to focus on.
Reading data from a CSV is trivial, there are many libraries that can help with that. Do a bit of research and pick one.
Create a class which holds the properties you need for validation checks and also those you want saved in the database.
Your goal is to create a list of these objects, one per row in csv. Of course, you may not be able to read everything in one go depending on how much data your csv holds, but you can pick a library which can deal with whatever size you have.
Now you have a list of objects. Write an algorithm which determines what is valid and what not, based on the rules you need. Your goal here is to end up with a possibly smaller list of the same objects, chucking out the invalid ones.
Save whatever is left in the database.
You need to start thinking about how you organize you code, don't just throw everything into the Click event of a button. You can create a model class to hold your objects, maybe create a separate class library where you can put your csv reading method.
Another class library perhaps for your filtering algorithm(s).
Your Click event should be fairly slim and only call library methods when it needs to do something. This is separation of concerns or SOC, which is a Solid Principle.
I am not sure how you plan to validate the datapoints, but the code below shows how to pull data from a CSV and load it into a SQL Server table.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Configuration;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string server = "EXCEL-PC\\EXCELDEVELOPER";
string database = "AdventureWorksLT2012";
string SQLServerConnectionString = String.Format("Data Source={0};Initial Catalog={1};Integrated Security=SSPI", server, database);
string CSVpath = #"C:\Users\Ryan\Documents\Visual Studio 2010\Projects\Bulk Copy from CSV to SQL Server Table\WindowsFormsApplication1\bin"; // CSV file Path
string CSVFileConnectionString = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};;Extended Properties=\"text;HDR=Yes;FMT=Delimited\";", CSVpath);
var AllFiles = new DirectoryInfo(CSVpath).GetFiles("*.CSV");
string File_Name = string.Empty;
foreach (var file in AllFiles)
{
try
{
DataTable dt = new DataTable();
using (OleDbConnection con = new OleDbConnection(CSVFileConnectionString))
{
con.Open();
var csvQuery = string.Format("select * from [{0}]", file.Name);
using (OleDbDataAdapter da = new OleDbDataAdapter(csvQuery, con))
{
da.Fill(dt);
}
}
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(SQLServerConnectionString))
{
bulkCopy.ColumnMappings.Add(0, "MyGroup");
bulkCopy.ColumnMappings.Add(1, "ID");
bulkCopy.ColumnMappings.Add(2, "Name");
bulkCopy.ColumnMappings.Add(3, "Address");
bulkCopy.ColumnMappings.Add(4, "Country");
bulkCopy.DestinationTableName = "AllEmployees";
bulkCopy.BatchSize = 0;
bulkCopy.WriteToServer(dt);
bulkCopy.Close();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
}
}

Database connections: How to use c# 4.0

Beginner:
Hi Guys - looking for some help to see how should i open and close database connections.
Problem i am trying to resolve:
I have a set of stored procedures which needs to be executed in the data access layer.
My service call the DA method Get(Request req) as:
public Data Get(Request request)
{
var data = new Data();
data = GetData();
data.AppleData = GetGrapeData();
data.OrangeData = GetGrapeData();
data.GrapeData = GetGrapeData();
return data;
}
where all the getmethods getdata, getgrapedata etc are private methods in the Data access class and different SP's are called in each methods.
Now in each method i am opening and closing the database connection as:
{ try{
using (var connection = new SqlConnection(connectionString)
using (var command = connection.CreateCommand())
{
connection.open();
ExecuteSP();
connection.Close();
}
}catch()
{
}
}
Now
Is there any way i can do this so i have to open/ close the connection just once?
I am doing try catch in each private method. is that ok?
Is there any issue in the way i am doing it above?
Yes, you can open the connection just once. You could use a class or something to manage this, but that seems overkill to me for a simple scenario.
public Data Get(Request request)
{
using (var connection = new SqlConnection(connectionString))
{
try
{
connection.open();
var data = new Data();
data = GetData(connection);
data.AppleData = GetGrapeData(connection);
data.OrangeData = GetGrapeData(connection);
data.GrapeData = GetGrapeData(connection);
return data;
}
finally
{
connection.close()
}
}
}
And then in the methods that call the stored procedure:
private Date GetDate(SqlConnection connection)
{
using (var command = connection.CreateCommand())
{
return ExecuteSP();
}
}
You can put exception handling wherever you'd like, but if you aren't going to do anything with the exception, then you absolutely should not catch it.
With SQL Server, you don't want to leave connections open any longer than you need to. Other parts of the system, or another system, can be waiting for them.
And second on the ORM - either EF or NHibernate does this much better than most programmers.
So, to support the example I mentioned in my comment above, you could do something like this:
// This is your main class.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void SomeMethod(object sender, EventArgs e)
{
ConnectToSql connToSql = new ConnectToSql(); // Instantiate the new class here.
connToSql.SqlConnection(); // Use the new class
}
}
}
// This is the class that manages your SqlCommand and connection objects
namespace WindowsFormsApplication1
{
class ConnectToSql
{
public void SqlConnection()
{
try
{
string strConn = "Some connection string here.";
string strCmd = "Some Sql query string here.";
// Create your connection object.
using (SqlConnection sqlConn = new SqlConnection(strConn))
{
// Create your command object and pass it the connection.
using (SqlCommand sqlCommand = new SqlCommand(strCmd, sqlConn))
{
sqlConn.Open();
// Do some work here.
sqlConn.Close();
}
}
}
catch (SqlException sqlExc)
{
throw;
}
catch (Exception exc)
{
throw;
}
}
}
A few things to note here:
This isn't the best approach. As was mentioned in comments, an ORM may be a better fit.
Each time you need to open the connection, you will need to use the new class so, it's best to instantiate it at the top-level of your class.
The using keyword will manage your connection and command objects for you since they both implement IDisposable.

Creating .csv file from an Access table using C#

I am trying to write a program which creates a .csv file from an Access table. I'm not sure how to do this and everything I've found while researching this is how to do the opposite, creating an Access table from a .csv file.
So far, I have created a windows forms application that allows the user to select a data path to the access directory (.mdb) and then after pushing the "Go" button, a list of the tables in the directory is shown in a listbox.
What I need to do next, which I have no idea how to, is allow the user to select one of the tables, which would then create a .csv file from the selected table. Here is my code so far:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Data.Common;
namespace TranslatorHelper
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnPath_Click(object sender, EventArgs e)
{
string dialogText = "";
// Show the dialog and get result.
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK) // Test result.
{
dialogText = openFileDialog1.ToString();
dialogText = dialogText.Replace("System.Windows.Forms.OpenFileDialog: Title: , FileName: ", "");
txtDataPath.Text = dialogText;
}
}
private void btnGetTables_Click(object sender, EventArgs e)
{
// Microsoft Access provider factory
DbProviderFactory factory =
DbProviderFactories.GetFactory("System.Data.OleDb");
DataTable userTables = null;
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+txtDataPath.Text;
// We only want user tables, not system tables
string[] restrictions = new string[4];
restrictions[3] = "Table";
connection.Open();
// Get list of user tables
userTables = connection.GetSchema("Tables", restrictions);
}
// Add list of table names to listBox
for (int i = 0; i < userTables.Rows.Count; i++)
lstTables.Items.Add(userTables.Rows[i][2].ToString());
}
private void lstTables_SelectedIndexChanged(object sender, EventArgs e)
{
}
Please offer any advice you can, anything is appreciated, I'm really stuck here.
Perhaps I can shove you in the proper direction:
You have the start, which is the DbConnection. You can then create a DbCommand from that:
DbCommand command = connection.CreateCommand();
From there, you can assign text, such as:
command.CommandText = "SELECT * FROM " + tableName; //you might have to wrap the table name with quotes or square brackets!
Then you can get a reader:
DbDataReader reader = command.ExecuteReader(CommandBehavior.Default);
Once you have the reader, you've got the data, meaning you can then:
DataTable dt = new DataTable("MyNewTable");
dt.Load(reader);
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn dc in row.Columns)
{
if (!String.IsNullOrEmpty(sb.ToString()))
sb.Append(",");
sb.Append(row[dc.ColumnName].ToString());
}
sb.Append("\n");
}
To get the ListBox selection, you could use:
lstTables.SelectedItem.ToString()
That should give you the item, or in your case a table name. Don't forget that certain words are reserved in SQL (and it also depends on which SQL it is), so you might have to be careful using the table name directly in the SQL string for the CommandText parameter.
Also, I would see no need to use a SelectedIndexChanged event handler unless you need to do something immediately upon the user making a selection. If the behavior you want from the user is to make a selection and then click a button to start a process, then it's unnecessary to handle the change.

C# passing information

Sorry in advance im going to try and explain this as best as possible....
I have 2 asp.net pages one named membermaster and the second named memberdetails. I created a class library which contains 2 functions
My first function returns a list depending on the search result...
I added a linkbutton to the gridviews first column which when clicked it passes through querystring the membershipgen. What i wanted to do is for my second function i created this
public DataTable GetMembers(int MEMBERSHIPGEN)
{
DataTable table = null;
SqlConnection con = null;
SqlCommand cmd = null;
SqlDataAdapter ad = null;
SqlParameter prm = null;
try
{
table = new DataTable();
using (con = new SqlConnection(connectionString))
{
using (cmd = new SqlCommand("usp_getmemberdetail", con))
{
using (ad = new SqlDataAdapter(cmd))
{
prm = new SqlParameter("#MEMBERSHIPGEN", SqlDbType.Int);
prm.Value = MEMBERSHIPGEN;
cmd.Parameters.Add(prm);
ad.Fill(table);
}
}
}
}
catch (Exception ex)
{
//write your exception code here
}
return table;
}
In the attempt to try and send the membershipgen to this and it return the results. But once i compile the DLL and add it to my project I am not sure how i would reference this function to populate individual textboxes and labels with the information.
What I am trying to do is when a user clicks the viewdetails button on the gridview I can then use that membershipgen that I passed through querystring to populate the page through a stored procedure but the smarts would be stored in a DLL.
You probably want your method to return a value. Currently the return type is void, so the values it populates internally just go away when the call stack leaves the method. It sounds like you want something like this:
public DataTable GetMembers(int MEMBERSHIPGEN)
Then, in your method, after you've populated the DataTable and exited the using blocks, you'd do something like this:
return table;
This would return the DataTable to whatever called the method. So your page would have something like this:
DataTable table = GetMembers(membershipgen);
So the page would be responsible for:
Get the membershipgen value from the input (query string)
Call the method and get the result of the method
Display the result from the method (bind to a grid? or whatever you're doing to display the data)
And the method is responsible for:
Interact with the database
This is a good first step toward the overall goal of "separation of concerns" which is a very good thing to do. You can continue down this path by always asking yourself what each method, class, etc. should be responsible for. For example, your GetMembers method should also be responsible for ensuring that the value passed to it is valid, or that the value returned from it is not null.
You need to change GetMembers to return data instead of void. If you want to use DataTables, you can just modify your code to this:
public DataTable GetMembers(int MEMBERSHIPGEN)
{
DataTable table = new DataTable();
SqlConnection con = new SqlConnection(connectionString);
using (SqlCommand cmd = new SqlCommand("usp_getmemberdetail", con))
{
using (SqlDataAdapter ad = new SqlDataAdapter(cmd))
{
SqlParameter prm = new SqlParameter("#MEMBERSHIPGEN", SqlDbType.Int);
prm.Value = MEMBERSHIPGEN;
cmd.Parameters.Add(prm);
ad.Fill(table);
return table;
}
Then in your Page_Load it might be something like this (more robust than this hopefully):
{
DataTable table = yourDll.GetMembers(Convert.ToInt32(Request.QueryString["membership"]));
label1.Text = Convert.ToString(table.rows[0]["Name"]);
}
One way to go might be to construct the button so that it navigates to a url along the lines of:
http://localhost/DetailPage.aspx?membershipgen=4
Then in the load of the DetailPage.aspx:
Page_Load(Object sender, EventArgs e)
{
if (!this.IsPostback)
{
int membershipgen;
if (int.TryParse(Request.QueryString["membershipgen"], out membershipgen)
{
//Get the data (replace DataAccess with the name of your data access class).
//Also, you probably want to change GetMembers so it returns the data.
DataTable table = DataAccess.GetMembers(membershipgen);
//TODO: Display the results
}
}
else
{
//Display an error
}
}

Categories

Resources