C# - Non-latin characters doesnt appear properly in database Visual Studio - c#

Here is my code which inserts into database the elements in the textboxes of a dynamic gridview. The code works perfectly but my problem is that the inserted elements that are typed in non-latin characters (greek characters) does not appear propely in database and instead they appear like that:
http://i.stack.imgur.com/pwVTf.jpg
Please can you tell me what to do in order to insert the greek characters properly? Here is the code:
private void InsertRecords(StringCollection sc)
{
StringBuilder sb = new StringBuilder(string.Empty);
string[] splitItems = null;
const string sqlStatement = "INSERT INTO P_interventions (Date,P_Id,Simeio,Aitio,Etos,Therap) VALUES";
int id = Convert.ToInt32(Session["pa_id"]);
foreach (string item in sc)
{
if (item.Contains(","))
{
splitItems = item.Split(",".ToCharArray());
sb.AppendFormat("{0}(#Date, #p_id ,'{1}','{2}','{3}','{4}'); ", sqlStatement, splitItems[0], splitItems[1], splitItems[2], splitItems[3]);
}
}
using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
connection.Open();
using (SqlCommand cmd = new SqlCommand(sb.ToString(), connection))
{
cmd.Parameters.AddWithValue("#p_id", id);
cmd.Parameters.AddWithValue("#Date", DateTime.Now.ToShortDateString());
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
lblMessage.ForeColor = System.Drawing.Color.Green;
lblMessage.Text = "The records have benn inserted successfuly!";
}
protected void BtnSave_Click(object sender, EventArgs e)
{
//εγχειρήσεις
int rowIndex = 0;
StringCollection sc = new StringCollection();
if (ViewState["CurrentTable"] != null)
{
DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"];
if (dtCurrentTable.Rows.Count > 0)
{
for (int i = 1; i <= dtCurrentTable.Rows.Count; i++)
{
//extract the TextBox values
TextBox box1 = (TextBox)Gridview1.Rows[rowIndex].Cells[1].FindControl("TextBox1");
TextBox box2 = (TextBox)Gridview1.Rows[rowIndex].Cells[2].FindControl("TextBox2");
TextBox box3 = (TextBox)Gridview1.Rows[rowIndex].Cells[3].FindControl("TextBox3");
DropDownList ddl2 = (DropDownList)Gridview1.Rows[rowIndex].Cells[4].FindControl("DropDownList2");
//get the values from TextBox and DropDownList
//then add it to the collections with a comma "," as the delimited values
sc.Add(string.Format("{0},{1},{2},{3}", box1.Text, box2.Text, box3.Text, ddl2.SelectedItem.Text));
rowIndex++;
}
//Call the method for executing inserts
InsertRecords(sc);
}
}

Since you use nchar fields in your database (as mentioned in a comment), your database already supports Unicode strings. However, you are passing the values you want to insert as non-Unicode string literals in your SQL:
'...'
You need to pass them as Unicode strings:
N'...'
Now don't just put an N in front of your string literals: There's something else you are doing wrong: You are passing user-supplied values by string concatenation, which is a serious security and stability issue. Use parameters instead - you already know how to work with parameters, since you do it for #p_id and #Date. Do the same for your string values. This will also fix the Unicode issue, since AddWithValue defaults to a Unicode parameter type for strings.

I think you have to use the Unicode data types in the database instead of the regular ones (ex:instead of Varchar use NVarchar).
Also in the your code use the N before the string fields Like
sb.AppendFormat("{0}(#Date, #p_id ,N'{1}',N'{2}',N'{3}',N'{4}'); ", sqlStatement, splitItems[0], splitItems[1], splitItems[2], splitItems[3]);

Related

Convert textbox to multi-valued, parameterized SQL query

I'm a newbie when it comes to C#, but have some experience with C, Python and MATLAB. I wrote a simple C# program that takes in some user input and converts it into a (parameterized) SQL query. I've successfully converted the datetimepicker into a SQL query; however, I have another parameter (serial numbers) that the user would input into a textbox. They can enter multiple serial numbers, separated by commas. Once the user clicks on 'Submit', the SQL query is sent and the results displayed in a dataGridView.
It works with a single value (i.e. a single serial number), but when I try to put in multiple values, it doesn't work.
I've tried some suggestions like separating the textbox string into an array of values.
private DataTable GetResults()
{
DataTable dtResults = new DataTable();
string connString = ConfigurationManager.ConnectionStrings["dbx"].ConnectionString;
using (SqlConnection con = new SqlConnection(connString))
{
using (SqlCommand cmd = con.CreateCommand())
{
string[] numbers = textBox2.Text.Split(',');
var parameters = new string[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
parameters[i] = string.Format("#SN{0}", i);
cmd.Parameters.AddWithValue(parameters[i], numbers[i]);
}
cmd.CommandText = string.Format("SELECT [TestDate],[ParamName],[SerialNumber],[TestDataID],[MeasuredValue]," +
"[MaximumLimit],[MinimumLimit],[PassResult] FROM [dbo].[Device.ParametricTestResults] " +
"WHERE SerialNumber IN ({0}) " +
"AND (TestDate BETWEEN (#start) AND (#end)) " +
"AND PassResult = 1", string.Join(", ", parameters));
cmd.Parameters.AddWithValue("#start", dateTimePicker1.Text);
cmd.Parameters.AddWithValue("#end", dateTimePicker2.Text);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
dtResults.Load(reader);
}
}
return dtResults;
}
And the 'Submit' button has the following code attached to it:
private void button12_Click(object sender, EventArgs e)
{
TestResultsdataGridView.DataSource = GetResults();
}
Again, the datagridview should display entries for multiple serial numbers, but it only works for one.

Pass multiple string parameters to SQL Server procedure [duplicate]

This question already has answers here:
Passing a varchar full of comma delimited values to a SQL Server IN function
(27 answers)
Closed 5 years ago.
I have a stored procedure that uses the IN statement in the select condition.
SELECT *
FROM vwCashTransactions
WHERE TransactionTimeStamp BETWEEN '2017-01-30 ' AND '2017-12-01'
AND Country IN ('MY', 'BD')
ORDER BY TransactionTimeStamp DESC
I need to pass the country string from backend code.
This is the code I have written
if (manageCountries != null && manageCountries.Trim().Length > 0)
{
string[] words = manageCountries.Split(',');
string queryManageString = "";
int i = 0;
foreach (string word in words)
{
if (i != 0)
{
queryManageString += "','";
}
i++;
queryManageString += "'" + word + "'";
}
_DataTable = Global.DatabaseServices.GetTransactionReport("", startPeriod, endPeriod, queryManageString);
Somehow I am not getting the values. I am sure the issue is with the querymanageString. The way it is built is missing something. Can someone give an idea how I can achieve it?
Here's the code for calling the database:
public DataTable GetTransactionReport(string AccountCode, DateTime FromDate, DateTime ToDate, string ManagedCountry)
{
DataTable dataTable = new DataTable();
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.CommandText = "[GetTransactionReport]";
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("#AccountCode", AccountCode);
sqlCommand.Parameters.AddWithValue("#FromDate", FromDate);
sqlCommand.Parameters.AddWithValue("#ToDate", ToDate);
sqlCommand.Parameters.AddWithValue("#ManagedCountry", ManagedCountry);
sqlCommand.CommandTimeout = 300;
ExecuteQuery(dataTable, sqlCommand);
sqlCommand.Dispose();
return dataTable;
}
public int ExecuteQuery(DataTable dt, SqlCommand cmd)
{
int rowCount = 0;
SqlDataAdapter da = null;
try
{
if (cmd.Connection == null)
cmd.Connection = GetSqlConnection();
da = new SqlDataAdapter();
da.SelectCommand = cmd;
rowCount = da.Fill(dt);
}
catch (Exception ex)
{
throw new DatabaseException(ex);
}
finally
{
cmd.Connection.Close();
cmd.Connection.Dispose();
cmd.Connection = null;
da.Dispose();
}
return rowCount;
}
It's not very clear how you pass the parameters, but it seems that you pass a delimited string. This will not work. Your procedure needs a list of country ids, not a string with a delimiter.
You can either do some magic in the stored procedure, splitting string and stuff like that, or create your own type.
Try something like this:
CREATE TYPE [dbo].[StringList] AS TABLE
([StringValue] [varchar](200) NULL)
Then your stored procedure has a parameter of type StringList, which can be used just like a normal table:
ALTER PROCEDURE [dbo].[MySproc]
#ids AS dbo.StringList READONLY
AS
BEGIN
SET NOCOUNT ON;
...etc..
And, finally, in your code use a DataTable for the values:
DataTable idsDT = new DataTable();
idsDT.Columns.Add("StringValue", typeof(string));
// fill datatable here
And the command parameter should be SqlDbType.Structured
var cmd = new SqlCommand(....)
SqlParameter countryParam = cmd.Parameter.AddWithValue("ids", idsDT);
countryParam.SqlDbType = SqlDbType.Structured;
It seems, there is something wrong in your for loop where you create comma seperated single quote string. Update for loop with below:
string[] words = manageCountries.Split(',');
string queryManageString = "";
int i = 0;
foreach (string word in words)
{
if (i != 0)
{
queryManageString += ",'" + word + "'";
}
else
{
queryManageString += "'" + word + "'";
}
i++;
}
OR if you don't want to go with for loop, here is one line solution
queryManageString = string.Join(",", words.Select(x => string.Format("'{0}'", x)));

Split value from StringCollection to get as parameters

how to split into a string array and pass them to command parameters or hiddenfield, just need to split the string "S0010M,AZI002M,3,12/26/2013 12:00:00 AM,VDIQ20"
to pass with parameters like
cmd.Parameters.AddWithValue("#DealerCode", "S0010M");
cmd.Parameters.AddWithValue("#Code", "AZI002M");
cmd.Parameters.AddWithValue("#Qty", 33);
cmd.Parameters.AddWithValue("#ExpireDate", "12/26/2015");
cmd.Parameters.AddWithValue("#BatchNumber", "VDIQ20");
i have big problem about this .. please can you help me to fix this , beaus still learning the subject..
after click on Return button , take the data from gridview, it can be more than one rows.
protected void btnReturn_Click(object sender, EventArgs e)
{
int rowIndex = 0;
StringCollection SetDEL_Stores = new StringCollection();
if (ViewState["CurrentData"] != null)
{
DataTable dtCurrentTable = (DataTable)ViewState["CurrentData"];
DataRow drCurrentRow = null;
if (dtCurrentTable.Rows.Count > 0)
{
for (int i = 1; i <= dtCurrentTable.Rows.Count; i++)
{
var DealerCode = HFDealerCode.Value;
var ItemIdentityCode = (Label)GridViewSalesReturn.Rows[rowIndex].Cells[2].FindControl("ItemIdentityCode");
var Qty = (Label)GridViewSalesReturn.Rows[rowIndex].Cells[8].FindControl("Quantity");
var ExpireDate = (Label)GridViewSalesReturn.Rows[rowIndex].Cells[6].FindControl("ExpireDate");
var BatchNumber = (Label)GridViewSalesReturn.Rows[rowIndex].Cells[7].FindControl("BatchNumber");
CultureInfo ci = new CultureInfo("en-GB");
SetDEL_Stores.Add(DealerCode + "," + ItemIdentityCode.Text + "," + decimal.Parse(Qty.Text) + "," + DateTime.ParseExact(ExpireDate.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture) + "," + BatchNumber.Text);
rowIndex++;
}
InsertDEL_Stores(SetDEL_Stores);
}
}
}
//in InsertDEL_Stores(SetDEL_Stores); event , taking the stringline separated with "," ,,
private void InsertDEL_Stores(StringCollection SC_PurLinr)
{
String strConnString = ConfigurationManager.ConnectionStrings["CBConnectionString"].ConnectionString;
DataSet ds = new DataSet();
SqlConnection con = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand("sp_DEL_Stores_IU", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#DealerCode", SC_PurLinr[0]);
cmd.Parameters.AddWithValue("#Code", SC_PurLinr[1]);
cmd.Parameters.AddWithValue("#Qty", SC_PurLinr[2]);
cmd.Parameters.AddWithValue("#ExpireDate", SC_PurLinr[3]);
cmd.Parameters.AddWithValue("#BatchNumber", SC_PurLinr[4]);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
It is not clear why you need a string collection first. If you want to keep the contents of the single rows in the GridView then start defining a class for your items where every single field is typed correctly (string for strings, numeric for numerics and datetime for dates) Copying the content of the grid in a string collection is just a waste of time and memory because every time you need to use the values stored in the string collection you need to find the correct string and split it to the individual fields.
I could just offer a pseudocode here because I haven't the possibility to test it.
(As an example I have named this class MyItem, but you could call it as you wish)
public class MyItem
{
public string DealerCode;
public string ItemCode;
public int Quantity;
public Datetime ExpireDate;
public string BatchNumber;
}
Then in your loop
// To keep the content of the grid keyed on the BatchNumber field
Dictionary<string, MyItem> items = new Dictionary<string, MyItem>();
for (int rowIndex = 0; i < dtCurrentTable.Rows.Count; i++)
{
MyItem itm = new MyItem();
itm.DealerCode = HFDealerCode.Value.ToString();
itm.ItemCode = GetGridValue(rowIndex, 2, "ItemIdentityCode");
itm.Quantity = Convert.ToDecimal(GetGridValue(rowIndex, 8, "Quantity");
itm.ExpireDate = Convert.ToDateTime(GetGridValue(rowIndex, 6, "ExpireDate");
itm.BatchNumber = GetGridValue(rowIndex, 7, "BatchNumber");
// Add the item to the dictionary for future reuses, however if you just want to store
// the item in the database this line is not needed
items.Add(itm.BatchNumber, itm);
// notice that the storing is executed inside the loop that extracts the values
// so every row is updated/inserted in the database
InsertDEL_Stores(itm);
}
GetGridValue is a method that you should write taking the parameters passed and returning a string with the value searched on the current row of your gridview. This could be simple as
string GetGridValue(int rowIndex, int cellIndex, string controlName)
{
Control c = GridViewSalesReturn.Rows[rowIndex].Cells[cellIndex].FindControl(controlName);
return (c != null ? c.Value.ToString() : "");
}
but you need to test it for its correctness.
However, after that you have an istance of MyItem class that you could store in the dictionary for future reuses or just pass it to the database working procedure
private void InsertDEL_Stores(MyItem itm)
{
String strConnString = ConfigurationManager.ConnectionStrings["CBConnectionString"].ConnectionString;
using(SqlConnection con = new SqlConnection(strConnString))
using(SqlCommand cmd = new SqlCommand("sp_DEL_Stores_IU", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#DealerCode", itm.DealerCode);
cmd.Parameters.AddWithValue("#Code", itm.ItemCode);
cmd.Parameters.AddWithValue("#Qty", itm.Quantity);
cmd.Parameters.AddWithValue("#ExpireDate", itm.ExpireDate);
cmd.Parameters.AddWithValue("#BatchNumber", itm.BatchNumber);
con.Open();
cmd.ExecuteNonQuery();
}
}
I am aware that this code could raise more questions than the one that you try to resolve, neverless I think that this is more OOP than a simple string split
To split a string using commas as the separator character do the following
String[] values = str.split(",");
Then you can access the array in the following way
values[0];
But since your question is a bit confusing I suggest you read well the comments by other contributors what best suits your needs, how you are passing those values to the command parameters. Certainly, dictionaries and lists are more efficient than String collections

Passing Column name as string in mysql Insert query

this is what i am trying to do after receiving string from the serial port. i get whitespace between the data so i put two loops to eliminate them. i want to recieve data spanning multiple columns and a single row for every single run of do while loop.. Thanks in Advance
string text = sp.readline();
for (int i = 0; i < text.Length; )
{
p = text[i].ToString();
if (p != " ")
{
do
{
x += text[i].ToString();
s = text[i].ToString();
i++;
} while (s != " ");
try
{
string col = "column" + no.ToString();
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "INSERT INTO testdata("+col+")VALUES(?data)";
cmd.Parameters.Add("?data", MySqlDbType.VarChar).Value = x;
cmd.ExecuteNonQuery();
x = "";
p = "";
no++;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
} i++;
}
Sorry to say, you cannot, in any dialect of SQL, provide a table or column name as a bindable variable (or parameter). If it's working for MySQL that's terrific, but if you change over to any other DBMS make and model, it will suddenly stop working.
Also, INSERT means create a new row. You'll either need to insert all the column values at once in a single INSERT statement, or figure out how to INSERT one row and then UPDATE it for each new column value.
if you want to insert a single row having multiple column, then for loop is not required
following is for three columns
int no = 2;
cmd.CommandText = "INSERT INTO testdata(?col1,?col2,?col3)VALUES(?data1,?data2,?data3)";
cmd.Parameters.Add("?col1", MySqlDbType.String).Value = col1;
cmd.Parameters.Add("?col2", MySqlDbType.String).Value = col2;
cmd.Parameters.Add("?col3", MySqlDbType.String).Value = col3;
cmd.Parameters.Add("?data1", MySqlDbType.VarChar).Value = x1;
cmd.Parameters.Add("?data2", MySqlDbType.VarChar).Value = x2;
cmd.Parameters.Add("?data3", MySqlDbType.VarChar).Value = x3;
cmd.ExecuteNonQuery();

Split text and insert words in sql database

I want to select file contains .txt and split all strings in each text into array
then insert the divided words into sql database (word, counter) and count the repeated words in each text by counter that lead to unrepeated words in database tables>>
(1)-counter code is incorrect I found several errors in my code >> (i want to prevent a repeat of word at the same time calculate how many times repeated word in databases ,by using counter.)
(2)- my code has static path (just one text ),but I want user to select his file which he want to split. (browse.. button)
(3-)sql database could not show Arabic Words (?????)
namespace lib123
{
public partial class Form1 : Form
{
SqlConnection sqlConn;
SqlCommand sqlComm;
SqlDataAdapter sqlAdptr;
public Form1()
{
InitializeComponent();
sqlConn = new SqlConnection();
sqlComm = new SqlCommand();
sqlAdptr = new SqlDataAdapter();
sqlComm.Connection = sqlConn;
sqlComm.CommandType = CommandType.Text;
sqlConn.ConnectionString = "Data Source=007-PC\\SQLEXPRESS ;Initial Catalog= Email_DB;Integrated Security =True ";
}
private void Form1_Load(object sender, EventArgs e)
{
FillGrid();
}
private void button1_Click(object sender, EventArgs e)
{
if (sqlConn.State != ConnectionState.Open)
sqlConn.Open();
// sqlComm = sqlConn.CreateCommand();
StreamReader streamReader = new StreamReader(#"C:\Users\007\Desktop\spam-email\spamenglish.txt"); //get the file
string stringWithMultipleSpaces = streamReader.ReadToEnd(); //load file to string
streamReader.Close();
Regex r = new Regex(" +"); //specify delimiter (spaces)
string[] words = r.Split(stringWithMultipleSpaces); //(convert string to array of words)
int c = 1;
string strQry = "select ISNULL( max(id),0) as id from word_tb ";
sqlComm.CommandText = strQry;
int LastID = int.Parse(sqlComm.ExecuteScalar().ToString());
string x ;
String st = null;
for (int i = 0; i < words.Length; i++)
{
string y = words[i];
for (int j = 0; j <LastID; j++)
{
x = "select word from word_tb where id = j";
sqlComm.CommandText = x ;
if (x.Equals(y))
{
c = c + 1;
string sql = "INSERT INTO word_tb (count) VALUES ('" + c + "') where id = i";
sqlComm.CommandText = sql;
}
else
{
LastID = LastID + 1;
st += "INSERT INTO word_tb(id, word,count) VALUES('" + LastID + "', '" + words[i].ToString() + "','" + c + "');";
//st += "INSERT INTO word_tb(word) VALUES('" + words[i].ToString() + "');";
}
}
}
sqlComm.CommandType = CommandType.Text;
sqlComm.CommandText = st;
sqlComm.ExecuteNonQuery();
FillGrid();
}
private void FillGrid()
{
DataTable tbl = new DataTable();
string strQry = "select * from word_tb ";
sqlComm.CommandText = strQry;
sqlAdptr.SelectCommand = sqlComm;
sqlAdptr.Fill (tbl) ;
dataGridView1.DataSource = tbl;
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
//private void btnDelete_Click(object sender, EventArgs e)
//{
// string str = "DELETE FROM word_tb";
// sqlComm.CommandType = CommandType.Text;
// sqlComm.CommandText = str;
// sqlComm.ExecuteNonQuery();
// dataGridView1.Rows.Clear();
// }
}
}
1-counter code is incorrect I found several errors in my code?
you can use below code to split the File Text into words based on space as delimiter.
Code:
String strAllData = System.IO.File.ReadAllText(#"C:\Users\007\Desktop\spam-email\spamenglish.txt");
String[] words = strAllData.Split(' ');
2- my code has static path (just one text ),but I want user to select
his file which he want to split. (browse.. button) ?
you can use OpenFileDialog control to let user choose the file which he/she wants to work on.
Code:
OpenFileDialog fileDialog = new OpenFileDialog();
if (fileDialog.ShowDialog() == DialogResult.OK)
{
String strAllData = System.IO.File.ReadAllText(fileDialog.FileName);
String[] words = strAllData.Split(' ');
}
3 -sql database could not show Arabic Words (?????) ?
Sql Server can not show Uni Code characters when you fire a SELECT Query because you have created your table columns/feilds as varchar.
Solution: if you want to get the Arabic characters when you fire a SELECT query you should create your table columns to accept Uni Code characters using NVARCHAR datatype instead of VARCHAR. N stands for National language character set.
Step1 : create your table columns as NVARCHAR as below:
create table sample(
[name] [nvarchar](100) NOT NULL)
Step 2: Use N as prefix while inserting Data into NVARCHAR columns. N as prefix tells that all following characters are Uni Code characters.
Code:
INSERT INTO sample VALUES(N'لا أتكلم العربية');
Now if you fire a SELECT Query you will be able to see the Arabic Characters.

Categories