Override query in sql string possible? C# - c#

Currently I'm working with my local MSSQL database and when I make a connection all works good. However that is not the question I'm having right now; I want to make my code cleaner and I don't want to have duplicated code or almost duplicated code.
For now I'm working with one large class that holds all the methods to selecting, creating, updating and/or deleting an user. But I think it can be writen down better with an override string that rides over the sql string inside the code.
Only thing is that I'm (for now) a complete noob and have no idea how to accomplish this... please help? As an example I've set the two regions, might change them to classes, below.
#region Select Data from Database
public DataTable Select()
{
// static method to connect to database
SqlConnection conn = new SqlConnection(myconnstring);
// to hold the data from database
DataTable dt = new DataTable();
try
{
// sql query to get date from database
String sql = "SELECT * FROM tbl_users";
// for executing command
SqlCommand cmd = new SqlCommand(sql, conn);
// getting data from database
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
// database connection open
conn.Open();
// fill data in datatable
adapter.Fill(dt);
}
catch(Exception ex)
{
// throw message if any error accures
MessageBox.Show(ex.Message);
}
finally
{
// closing connection
conn.Close();
}
// return value in datatable
return dt;
}
#endregion
#region Search User on Database using KeyWords
public DataTable Search(string keywords)
{
// static method to connect to database
SqlConnection conn = new SqlConnection(myconnstring);
// to hold the data from database
DataTable dt = new DataTable();
try
{
// sql query to get date from database
String sql = "SELECT * FROM tbl_users WHERE id LIKE '%"+keywords+"%' OR first_name LIKE '%"+keywords+"%' OR last_name LIKE '%"+keywords+"%' OR username LIKE '%"+keywords+"%'";
// for executing command
SqlCommand cmd = new SqlCommand(sql, conn);
// getting data from database
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
// database connection open
conn.Open();
// fill data in datatable
adapter.Fill(dt);
}
catch (Exception ex)
{
// throw message if any error accures
MessageBox.Show(ex.Message);
}
finally
{
// closing connection
conn.Close();
}
// return value in datatable
return dt;
}
#endregion

Step 1. Read https://xkcd.com/327/ and whatever solution you go with fix id LIKE '%"+keywords+"%'
I encourage you to research an object mapper, like Dapper which will make your methods return types (e.g. User) and not raw DataTables. An ORM can help pushing you into the pit of success.
As for reuse you can notice that your methods that do SELECT look very similar so you could make a helper method DataTable ExecuteSelect(string sql) which you could reuse from your Search and Select methods.
You really must fix this '%"+keywords+"%' issue. SQL injection is no joke.

Think about changing your entire concept and work with entity framework.
That way you create a connection to the DB and class for each main entity you have there.
Afterwards all your selects, updates, deletes etc will be automatic with all the functionality you have in MSSQL.

(This would be a mess as a comment)
First of all you must write code that is trustable and doesn't have unnecessary additions. ie:
#region Select Data from Database
public DataTable Select(string sql)
{
DataTable dt = new DataTable();
try
{
// getting data from database
SqlDataAdapter adapter = new SqlDataAdapter(sql, myconnstring);
// fill data in datatable
adapter.Fill(dt);
}
catch(Exception ex)
{
// throw message if any error accures
MessageBox.Show(ex.Message);
}
// return value in datatable
return dt;
}
#endregion
#region Search User on Database using KeyWords
public DataTable Search(string keywords)
{
// to hold the data from database
DataTable dt = new DataTable();
String sql = #"SELECT *
FROM tbl_users
WHERE id LIKE #pattern OR
first_name LIKE #pattern OR
last_name LIKE #pattern OR
username LIKE #pattern";
try
{
using (SqlConnection conn = new SqlConnection(myconnstring))
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("#pattern", SqlDbType.Varchar).Value = '%"+keywords+"%';
// database connection open
conn.Open();
// fill data in datatable
tbl.Load(cmd.ExecuteReader());
}
catch (Exception ex)
{
// throw message if any error accures
MessageBox.Show(ex.Message);
}
// return value in datatable
return dt;
}
#endregion
First spare time to understand why you should use parameters, how you would use then etc.
Next, you would quickly see that this pattern is not flexible and not worth to make into a class as is.
You should think about getting away from DataTable and DataSet as well. Look into Linq and Entity Framework (Linq To EF). Others already found the wheel for you. Read about different patterns like Repository pattern. And also read about different backends and their advantagaes\disadvantages, weighing it against your use cases, before coding specifically for one of them.

Related

How to execute a generic SQL Command in C#?

I am trying to write a Method that simply accepts a string which is an SQL Command and runs it against the pre-defined Database/Server ... This is what I have so far:
public class TSqlConnector : IDbConnector
{
private readonly string _connectionString;
public TSqlConnector(string conn)
{
_connectionString = conn;
}
public IEnumerable<object[]> ExecuteCommand(string query)
{
var res = new List<object[]>();
try
{
using (SqlConnection sql = new SqlConnection(_connectionString))
{
sql.Open();
SqlCommand cmd = new SqlCommand(query, sql);
var reader = cmd.ExecuteReader();
DataTable tbl = new DataTable();
while (reader.Read())
{
var dr = tbl.NewRow();
dr.ItemArray = new object[reader.FieldCount];
reader.GetValues(dr.ItemArray);
res.Add(dr.ItemArray);
}
}
return res;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
throw;
}
}
}
This code, however, gives me an error saying that
Input array is longer than the number of columns in this table.
I googled the error message, apparently I first have to define the DataTable's columns, using tbl.Add("ColumnName", typeof(type));
This however, completely undermines what I was trying to do - writing a generic version. All I wanted was some kind of construct which contains the information I would get from the SqlServer if I typed the same command into SSMS, I don't really care what hoops I have to jump through to read the data in C#; Using an object-Array for each row, having to manually cast each object into a string, int or whatever is perfectly acceptable, even a CSV-like string would be just fine
The only thing I don't want to do is add a definition for the table or a fixed amount of row. Each method that uses ExecuteCommand() will have to know what type of object-array is returned and that's fine but adding some complex data structure containing types and column names in addition to the SQL Commands seems like overkill.
Is there some easier way to achieve this?
What you have is an IDataReader from your cmd.ExecuteReader();
To load the results into a DataTable, you can use the Load method as follows:
var reader = cmd.ExecuteReader();
DataTable tbl = new DataTable();
tbl.Load(reader);
// now tbl contains the corresponding columns and rows from your sql command.
// Then you can return the ItemArrays from each row;
return tbl.Rows.Cast<DataRow>().Select(row => row.ItemArray);
I've used code like this to input a generic SQL query and return the results as a datatable. Of course, you'll have to parse out the results how you need them.
private DataTable QueryToTable(string sql, string cs)
{
var ds = new DataSet();
using (var adapter = new SqlDataAdapter(sql, cs))
{
adapter.Fill(ds);
}
return ds.Tables(0);
}

How do I use the datatable to retrieve data in my table from SQL Server in c #

i want to retrieve data from my database to my window that displays all information about a student in the "Student View" where I choose a studentid and then fill all the information. Thanks in advance this is my code.
Solution 1, but not effective because i have many students and its not read from my database.
public override DataTable getStudentData()
{
DataTable dt = new DataTable();
dt.Columns.Add("StudentID");
dt.Columns.Add("FirstName");
dt.Columns.Add("LastName");
dt.Columns.Add("Gender");
dt.Columns.Add("Streetadress");
dt.Columns.Add("ZipCode");
dt.Columns.Add("Birthdate");
dt.Columns.Add("StudentType");
dt.Columns.Add("City");
dt.Columns.Add("Country");
dt.Columns.Add("program");
dt.Columns.Add("PgmStartYear");
dt.Columns.Add("credits");
dt.Rows.Add("studentid", "Firstname", "Lastname", "Gender", "Adress", "Zipcode", "Birthdate", "Studenttype ", "City", "Country", "Programname", Startyear, credits);
return dt;
}
Solution that i want to be possible is something like this:
DataTable dt = new DataTable();
dt.Rows.Add(["studentid"].ToString());
dt.Rows.Add(["firstname"].ToString());
dt.Rows.Add(["lastname"].ToString());
dt.Rows.Add(["gender"].ToString());
dt.Rows.Add(["birthdate"].ToString());
dt.Rows.Add(["streetadress"].ToString());
dt.Rows.Add(["zipcode"].ToString());
dt.Rows.Add(["country"].ToString());
dt.Rows.Add(["city"].ToString());
dt.Rows.Add(["studenttype"].ToString());
dt.Rows.Add(["programname"].ToString());
dt.Rows.Add(["year"].ToString());
You need some kind of a tutorial or an article about loading from Database using C#....
The suggested answer before is one way (and will work perfectly)...
and you can find another way on this link:
Although since your are new to C# and still learning, i highly recommend you to follow the "Solution 2" provided in page which uses stored procedures instead of direct SQL, since its the correct way to connect to database.
You can use following function to retrieve data from SQL Server
using System.Data;
using System.Data.SqlClient;
public DataTable StudentView()
{
SqlConnection sqlCon = new SqlConnection(#"Server= localhost\SQLINSTANCENAME; Database= DBNAME; Integrated Security=True;");
SqlDataAdapter sqlDa = new SqlDataAdapter("QUERY", sqlCon);
DataTable dtbl = new DataTable();
sqlDa.Fill(dtbl);
return dtbl;
}
Replace
SQLINSTANCENAME with your own SQL Server instance name, e.g. SQLEXPRESS, SQL2008
DBNAME with your database name
QUERY with SELECT column-list FROM your-table
Thank you all. I have already connected to my database and try something like this:
try
{
SqlCommand read = new SqlCommand();
read.CommandType = CommandType.Text;
read.Connection = connect;
read.CommandText = "SELECT * FROM [viewstudent]";
SqlDataReader get;
get = read.ExecuteReader();
while (get.Read())
{
dt.Rows.Add(["studentid"].ToString(); get["firstname"].ToString(); get["lastname"].ToString(); get["gender"].ToString(); get["birthdate"].ToString(); get["streetadress"].ToString(); get["zipcode"].ToString(); get["country"].ToString();
get["city"].ToString(); get["studenttype"].ToString(); get["programname"].ToString(); get["year"].ToString(); get["credits"].ToString();
}
MessageBox.Show("Good!");
}
catch (Exception e)
{
MessageBox.Show("Error try again!");
}
connect.Close();
return dt;
}

Boost select statement performance of sqlite database in C#

I have a sqlite database consist of 50 columns and more than 1.2 million rows. I'm using System.Data.Sqlite to work with Visual Studio 2013 C# language.
I used a very simple code to retrieve my data from database but it is taking too much time.
private SQLiteConnection sqlite;
public MySqlite(string path)
{
sqlite = new SQLiteConnection("Data Source="+path+"\\DBName.sqlite");
}
public DataTable selectQuery(string query)
{
SQLiteDataAdapter ad;
DataTable dt = new DataTable();
try
{
SQLiteCommand cmd;
sqlite.Open();
cmd = sqlite.CreateCommand();
cmd.CommandText = query; //set the passed query
ad = new SQLiteDataAdapter(cmd);
ad.Fill(dt); //fill the datasource
}
catch (SQLiteException ex)
{
//exception code here.
}
sqlite.Close();
return dt;
}
And, the select statement is:
select * from table
As I told you, it is a very simple code.
I want to know how to boost select operation performance to get the appropriate result. for this code the process takes up to 1 minute which I want to get to less than 1 second.
and another thing is that there seems to be some tags for configuring sqlite database but I don't know where to apply them. could some one tell me how to configure sqlite database with System.Data.Sqlite;
Consider narrowing your result set by getting necessary columns or paging.

Insert data into Sql Compact

I have Handheld device that connect to Sql Server database, read the Sql server data and get it on the SQL Compact database that is located on device. This is my code:
public void InsertData() // Function insert data into SQL commapct database
{
dt = new DataTable();
dt = SqlServer_GetData_dt("Select id_price, price, id_item from prices", SqlCeConnection); // get data form sql server
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
string sql = "";
sql = "insert into prices" +
" ( id_prices, price,id_item) values('"
+ dt.Rows[i]["id_price"].ToString().Trim() + "', '"
+ dt.Rows[i]["price"].ToString().Trim() + "', '"
+ dt.Rows[i]["id_item"].ToString().Trim() + "')";
obj.SqlCE_WriteData_bit(sql, connection.ConnectionString);//insert into sql compact
}
}
}
public DataTable SqlServer_GetData_dt(string query, string conn)
{
try
{
DataTable dt = new DataTable();
string SqlCeConnection = conn;
SqlConnection sqlConnection = new SqlConnection(SqlCeConnection);
sqlConnection.Open();
{
SqlDataReader darSQLServer;
SqlCommand cmdCESQLServer = new SqlCommand();
cmdCESQLServer.Connection = sqlConnection;
cmdCESQLServer.CommandType = CommandType.Text;
cmdCESQLServer.CommandText = query;
darSQLServer = cmdCESQLServer.ExecuteReader();
dt.Load(darSQLServer);
sqlConnection.Close();
}
return dt;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
DataTable dt = new DataTable();
return dt;
}
}
public object SqlCE_WriteData_bit(string query, string conn)
{
try
{
string SqlCeConnection = conn;
SqlCeConnection sqlConnection = new SqlCeConnection(SqlCeConnection);
if (sqlConnection.State == ConnectionState.Closed)
{
sqlConnection.Open();
}
SqlCeCommand cmdCESQLServer = new SqlCeCommand();
cmdCESQLServer.Connection = sqlConnection;
cmdCESQLServer.CommandType = CommandType.Text;
cmdCESQLServer.CommandText = query;
object i = cmdCESQLServer.ExecuteScalar();
sqlConnection.Close();
return i;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return 0;
}
}
This is all work fine but the problem is that all this work very slow. I have 20 000 row that's need to be inserted into SQL compact database.
Is there any way for faster insert?
Thanks.
Aside from the obvious poor usage of the Connection for every call, you can greatly improve things by also eliminating the query processor altogether. That means don't use SQL. Instead open the destination table with TableDirect and a SqlCeResultset. The iterate through the source data (a DataTable is a bad idea, but that's a completely different thing) and use a series of CreateRecord, SetValues and Insert.
A pretty good example can be found here (though again, I'd use SetValues to set the entire row, not each individual field).
Reuse your connection and don't create a new connection for every INSERT statement.
Instead of passing a connection string to your SqlCE_WriteData_bit method, create the connection once in the InsertData method, and pass the connection object to SqlCE_WriteData_bit.
Put all the data into a DataTable and then use a SqlCeDataAdapter to save all the data with one call to Update. You may have to fiddle with the UpdateBatchSize to get the best performance.
Looking more closely, I see that you already have a DataTable. Looping through it yourself is therefore ludicrous. Just note that, as you have it, the RowState of every DataRow will be Unchanged, so they will not be inserted. I think that you can call DataTable.Load such that all RowState values are left as Added but, if not, then use a SqlDataAdapter instead, set AcceptChangesDuringFill to false and call Fill.
Is there any way for faster insert?
Yes, but it probably won't be "acceptably fast enough" when we're talking about inserting 20k rows.
The problem I can see is that you are opening a connection for every single row you are retrieving from SqlServer_GetData_dt, that is, you open a connection to insert data 20k times...opening a connection is an expensive transaction. You should build the whole query using a StringBuilder object and then execute all the insert statements in one batch.
This will bring some performance gains but don't expect it to solve you're problem, inserting 20k rows will still take some time, specially if indexes need to be re-built. My suggestion is that you should thoroughly analyse your requirements and be a bit smarter about how you approach it. Options are:
bundle a pre-populated database if possible so your app doesn't have to suffer the population process performance penalties
if not, run the insert process in the background and access the data only when the pre-population is finished

asp.net C# database table column to list

I have an asp.net project done in C# (my C# syntax is very rusty) and am using the built in database it creates with the project. I've created a table called aspnet_Tutorials that (for now) stores two columns of user submitted data: TutorialName and TutorialContent. Very simple, it's a learning project.
What I need to do is create a list from the first column of aspnet_Tutorials to use it to create a "directory" of the tutorials on a page. The part I'm having trouble with, mostly syntactically, is connecting to and iterating over the column to get the values into a list. Could anyone provide a straight forward example of this? And possibly explain what's going on in the code.
public class TutorialsDirDAL
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString);
SqlCommand cmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
public List<string> DisplayTutorials() //parameters? String qry?
{
//query the database table, foreach loop over the data, place it into a list?
}
}
I know how to write simple sql queries. But I've seen a couple different set ups for this in my Googling spree. I currently have the following for a query, feel free to pick it apart or offer a better solution than using a query.
cmd.CommandText = "SELECT * FROM ASPNET_TUTORIALS (TutorialTitle)"
+ "VALUES (#tutorialTitle)";
Thank you!
ebad86's answer is acceptable but since you are obviously learning I think introducing OO principals muddy the water with what you are trying to learn at this point.
Here is a basic method:
private void GetData()
{
//The object that will physically connect to the database
using(SqlConnection cnx = new SqlConnection("<your connection string>")
{
//The SQL you want to execute
SqlCommand cmd = new SqlCommand("SELECT * FROM ASPNET_TUTORIALS");
//Open the connection to the database
cnx.Open();
//execute your command
using (IDataReader dataReader = cnx.ExecuteReader(cmd))
{
//Loop through your results
while(dataReader.Read())
{
//do whatever to the data
ListItem item = new ListItem(Convert.ToString(dataReader["TutorialName"]));
lst.Items.Add(item);
}
}
}
}
This is all very straightforward. The part you are most interested in is the while loop though. The loop will go through all of the returned records and you can do whatever you need to do with them. In my example I have assumed that there is a ListBox named 'lst' and I am simply adding ListItems to it that will have the name of whatever 'TutorialName' is. You can make literally do whatever you need to do with the data at this point. To fit your example (returning a List) you would do this:
private List<string> GetData()
{
List<string> lst = new List<string>();
//The object that will physically connect to the database
using(SqlConnection cnx = new SqlConnection("<your connection string>")
{
//The SQL you want to execute
SqlCommand cmd = new SqlCommand("SELECT * FROM ASPNET_TUTORIALS");
//Open the connection to the database
cnx.Open();
//execute your command
using (IDataReader dataReader = cnx.ExecuteReader(cmd))
{
//Loop through your results
while(dataReader.Read())
{
lst.Add(Convert.ToString(dataReader["TutorialName"]));
}
}
}
return lst;
}
Please respond if you have any questions.
Well you can fetch using data reader and map to the object. I can give you some rough code, which could be like this:
using (IDataReader objDataReader = objDB.ExecuteReader(objCMD))
{
while (objDataReader.Read())
{
DataBaseObject obj = new DataBaseObject();
obj = MapObjectToList(objDataReader);
ObjectList.Add(obj);
}
objDataReader.Dispose();
}
// Mapping Function can be called somewhat like this:
private DataBaseObject MapObjectToList(IDataReader objDataReader)
{
DataBaseObject obj = new DataBaseObject();
obj.Prop1Name = base.GetDataValue<string>(objDataReader, "Column1Name");
obj.Prop2Name = base.GetDataValue<string>(objDataReader, "Column2Name");
return obj;
}
But this is just a rough idea how I would do it.

Categories

Resources