Too much connections to db using DataReader - c#

Every time i get a value from a response from a odbcconnection by datareader, i made a connection to the database (if i have a query that return 9 fields, i have 9 connection to db), and i want to do only 1 connection and retrieve all information. it's possible with datareader ? I need to use other method of connection ?
Best Regards.
Code:
string strSql = "SELECT G.COMPANY_ID, U.USER_ID, U.GROUP_ID, U.NAME, U.DISPLAY_NAME, U.EMAIL, U.IS_CORPORATE, U.CALL_PARK, U.CALL_PICKUP, U.PCHUNTING, U.OUT_OF_OFFICE, U.DND, U.HOTLINE, U.PIN, U.FORCE_PIN_CHECKED, U.PCHUNTING_TYPE, U.DND_END_TIMESTAMP, U.DND_CONTACT, U.OUT_OF_OFFICE_TYPE, U.LANGUAGE, U.AVAILABLE_TIMESTAMP, U.LAST_DIALLED_NUMBER, U.LAST_INCOMING_CALL, U.LAST_MISSED_CALL, U.CALL_PICKUP_GROUP_ID, U.HOTLINE_NUMBER, U.PORTAL_PASSWORD, U.PROFILE, U.MAIN_NUMBER, U.DUAL_OUTGOING_CTRANSFER, U.MY_CALL_PICKUP, U.VM_RECONNECT_NOTIFY, U.SPARE_STRING1, U.INSERT_DATE, U.INSERT_USER, U.UPDATE_DATE, U.UPDATE_USER " +
"FROM {0}_TT_USER U LEFT OUTER JOIN {0}_TT_GROUP G ON U.GROUP_ID = G.GROUP_ID " +
"WHERE USER_ID = :USER_ID ";
conn = new OdbcConnection(GetIpCntrxTimestenConnString(opCode));
cmd = new OdbcCommand(
string.Format(strSql
, config.GetIpCntrxEsmViewName(opCode))
, conn);
cmd.Parameters.AddWithValue(":USER_ID", user_id);
cmd.CommandType = CommandType.Text;
conn.Open();
dataReader = cmd.ExecuteReader();
object[] meta = new object[dataReader.FieldCount];
int NumberOfColums = dataReader.GetValues(meta);

No, you need another way to query.
Instead of one query per field, SELECT all 9 at once and close the connection right away.
Another problem with this approach is that there's no layering whatsoever. I wouldn't like mingling UI and database code together. There's no abstraction your way.

Try using a StringBuilder and AppendLine your select queries. Loop through your dbReader and store in an List thats the best i can come up with. I do understand you want one call with 9 different queries but either way there is going to be overhead on your sql machine or program machine.

Related

How to use value from SQL Server in C#

I got value from SQL Server using this C# code:
SqlDataReader reader = new SqlCommand("select Top 1 Client From _ClientName group by Client order by count(*) desc", sqlCon.ShardDB).ExecuteReader();
How can I use this value again to insert it into another table?
Just use name of the column begin returned from the database i.e "Client" here. If it is a string, you can use .ToString(). If it is another type, you need to convert it using System.Convert
string Value = reader["Client"].ToString();
First, for readability sake, try separating your code into separate lines, like so:
SQLReader reader;
SQLCommand SQLCmd = new SQLCommand();
SQLCmd.CommandText = "select Top 1 Client From _ClientName group by Client order by count(*) desc";
SQLCmd.Connection = sqlCon.SharedDB;
reader.Execute(SQLCmd);
If I understood your comment to Sajeetharan's previous answer, you want to know how to advance to the next result if your query returns more than one. Have you tried SQLReader.Read()?
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader(v=vs.110).aspx

Insert user defined variables in to the sql statements [duplicate]

This question already has answers here:
SqlCommand with Parameters
(3 answers)
Closed 8 years ago.
Hi this is my query
SELECT StraightDist FROM StraightLineDistances
WHERE (FirstCity='007' AND SecondCity='017');
How can I pass this in to sql statement?
I want to replace the city numbers '007' and '017' with variables
string destcity;
string tempcityholder1;
What I tried is this
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='" + tempcityholder1 + "' AND SecondCity='" + destcity + "');", mybtnconn2);
it didn't give me the expected output.
But when i tried with the original sql as given below it worked.
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='007' AND SecondCity='017');", mybtnconn2);
Can anyone point me the error here?
or a better solution.
This is for a personal application, security is not a must, so no need of parametrized queries. And I don't know how to implement parametrized queries with multiple parameters. If anyone can explain how to use a parametrized query it's great and I would really appreciate that. But just for the time being I need to correct this.
Any help would be great..
OK if with parametrized query
MY Work looks like this
SqlConnection mybtnconn2 = null;
SqlDataReader mybtnreader2 = null;
mybtnconn2 = new SqlConnection("");
mybtnconn2.Open();
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='007' AND SecondCity='017');", mybtnconn2);
mybtnreader2 = mybtncmd2.ExecuteReader();
while (mybtnreader2.Read())
{
MessageBox.Show(mybtnreader2.GetValue(0) + "My btn readre 2 value");
}
Can anyone give me a solution which doesn't complicate this structure.
If I use a parametrized query how can I edit
mybtnreader2 = mybtncmd2.ExecuteReader();
This statement?
This is the way to use parametrized queries:
string sqlQuery="SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity= #tempcityholder1 AND SecondCity=#destcity);"
SqlCommand mybtncmd2 = new SqlCommand(sqlQuery, mybtnconn2);
mybtncmd2.Parameters.AddWithValue("tempcityholder1", tempcityholder1 );
mybtncmd2.Parameters.AddWithValue("destcity", destcity);
It's always good practice to use parameters, for both speed and security. A slight change to the code is all you need:
var mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE FirstCity=#City1 AND SecondCity=#City2;", mybtnconn2);
mybtncmd2.Parameters.AddWithValue("#City1", "007");
mybtncmd2.Parameters.AddWithValue("#City2", "017");
Use prepared statements: it's both easy and secure.
command.CommandText =
"INSERT INTO Region (RegionID, RegionDescription) " +
"VALUES (#id, #desc)";
SqlParameter idParam = new SqlParameter("#id", SqlDbType.Int, 0);
SqlParameter descParam =
new SqlParameter("#desc", SqlDbType.Text, 100);
You really won't do this, because this is an open door to SQL injection.
Instead you should use Stored Procedures for that approach.
In case your not familiar with SQL injection, let's make it clear:
Assume that you have a database with a table called 'T_USER' with 10 records in it.
A user object has an Id, a Name and a Firstname.
Now, let's write a query that select a user based on it's name.
SELECT * FROM T_USER WHERE Name= 'Name 1'
If we take that value from C#, this can really take unexpected behaviour.
So, in C# code we will have a query:
string queryVal;
var command = "SELECT * FROM T_USER WHERE Name = '" + queryVal + "'";
As long as the user is nice to your application, there's not a problem.
But there's an easy way to retrieve all records in this table.
If our user passes the following string in QueryVal:
demo' OR 'a' = 'a
Then our query would become:
SELECT * FROM T_USER WHERE Name = 'demo' OR 'a' = 'a'
Since the second condition is always true, all the records are retrieved from this table.
But we can even go further:
If the same user uses the following value in queryVal:
demo'; DELETE FROM T_USER--
The full query becomes:
SELECT * FROM T_USER WHERE Name = 'demo'; DELETE FROM T_USER--'
And all our records our gone.
And we can even go further by dropping the table:
queryVal needs to be:
demo'; DROP TABLE T_USER--
I think you get it. For more information google on Sql Injection:

MySql Last Insert ID, Connector .net

I'm using the MySql Connector .net, and I need to get the insert id generated by the last query. Now, I assume the return value of MySqlHelper.ExecuteNonQuery should be the last insert id, but it just returns 1.
The code I'm using is:
int insertID = MySqlHelper.ExecuteNonQuery(Global.ConnectionString,
"INSERT INTO test SET var = #var", paramArray);
However insertID is always 1. I tried creating a MySql connection and opening/closing manually which resulted in the same behaviour
Just use LastInsertedId field
MySqlCommand dbcmd = _conn.CreateCommand();
dbcmd.CommandText = sqlCommandString;
dbcmd.ExecuteNonQuery();
long imageId = dbcmd.LastInsertedId;
1 is the no of records effected by the query here only one row is inserted so 1 returns
for getting id of the inserted row you must use scope_identity() in sqlserver and LAST_INSERT_ID() in MySql
Try to use this query to get last inserted id -
SELECT LAST_INSERT_ID();
Then, run DbCommand.ExecuteReader method to get IDataReader -
command.CommandText = "SELECT LAST_INSERT_ID()";
IDataReader reader = command.ExecuteReader();
...and get information from the reader -
if (reader != null && reader.Read())
long id = reader.GetInt64(0);
...do not forget to close the reader;-)
I had the same problem, and after some testing, I found out that the problem seem to be the connection method; you are using a connection string.
This is of course to make use of the automatic connection pool reuse, but in this case it gave me trouble.
The final solution for me is to create a new connection, execute the insert query, and then execute the last_insert_id(). On the same connection.
Without using the same connection, last_insert_id() might return anything, I don't know why, but guess it looses track of things as it can be different connections.
Example:
MySqlConnection connection = new MySqlConnection(ConnectionString);
connection.Open();
int res = MySqlHelper.ExecuteNonQuery(
connection,
"INSERT INTO games (col1,col2) VALUES (1,2);");
object ores = MySqlHelper.ExecuteScalar(
connection,
"SELECT LAST_INSERT_ID();");
if (ores != null)
{
// Odd, I got ulong here.
ulong qkwl = (ulong)ores;
int Id = (int)qkwl;
}
I hope this helps someone!
I know this is an old post, but I have been facing the same issue as Snorvarg. Using MySqlHelper, and using a connection string instead of a Connection object (to allow MySqlHelper to use connection pooling), SELECT LAST_INSERT_ID() would often give me the ID of the previous query that was executed, or other times it would return zero. I would then have to call SELECT LAST_INSERT_ID() a second time to get the correct ID.
My solution was to encapsulate everything between the query that's being executed, and the calling of SELECT LAST_INSERT_ID() in a TransactionScope. This forces MySqlHelper to stick to one connection instead of opening two separate connections.
So:
string sql = "INSERT INTO games (col1,col2) VALUES (1,2);");
string connectionString = "some connection string";
using (TransactionScope scope = new TransactionScope)
{
int rowsAffected = MySqlHelper.ExecuteNonQuery(connectionString, sql);
object id = MySqlHelper.ExecuteScalar(connectionString, "SELECT LAST_INSERT_ID();");
scope.Complete();
}
try below working solution in repository .
string query = $"INSERT INTO `users`(`lastname`, `firstname`, `email`, `createdate`, `isdeleted`) " +
$"VALUES ('{userEntity.LastName}','{userEntity.FirstName}','{userEntity.Email}','{userEntity.CreateDate}',{userEntity.IsDeleted});" +
$"SELECT LAST_INSERT_ID();";
var res= _db.ExecuteScalar(query);
return (int)(UInt64)res;

C# Equivalent of adodb recordsets

I am converting a VB6 windows application to C# using VS2008, V3.5. I have a SQL Server 2000 database I use for data storage and retrieval. One table holds a single record that is of type Int and is used for generating a quote number, ie, 123456. In VB6 I do the following:
OpenDBCon
Set rst = New ADODB.Recordset
rst.Open "SELECT idx From tblQuoteIdx", cn, adOpenDynamic, adLockPessimistic
Select Case rst.BOF
Case False
rst.MoveFirst
Me.txtRef = rst!idx
tID = rst!idx + 1
OKToContinue = True
Case False
'Do something
End Select
If OKToContinue = True Then
Set rst = New ADODB.Recordset
rst.Open "update tblQuoteIdx set idx = '" & tID & "' ", cn, adOpenDynamic,
adLockPessimistic
End If
CloseDBCon
In C# I currently am doing this:
SqlConnection conn = new SqlConnection();
conn.ConnectionString = Vars.connstring;
conn.Open();
SqlCommand sqlComm = new SqlCommand("Select idx from tblQuoteIdx", conn);
Int32 tt = (Int32)sqlComm.ExecuteScalar();
Int32 tt2 = tt++;
SqlCommand sqlComm2 = new SqlCommand("Update tblQuoteIdx set " +
"idx = " + tt2 + "", conn);
sqlComm.ExecuteNonQuery();
conn.Close();
Unfortunately I find now without a cursor lock of "adLockPessimistic" when several people hit the record at the same time multiple instances of the same index number can show up. If anyone could either explain how to use an ADODB.Recordset in C# for this specific purpose and or use record locks so as to lock the db record when needed, OR a better way within the .Net framework and C# principals to accomplish the same thing, I would be greatful. Many thanks in advance.
Noel
I believe you will find this article useful:
Pessimistic locking in ado.net
Basically you will need to wrap everything in a transaction that applies a lock on the records as soon as editing starts. This way no other method will be able to edit the values until the lock is released.

SQL connection string for microsoft access 2010 .accdb

I am doing a simple login form using winforms and access 2010 database (.accdb) in C#.
I have the following code and it seems that the connection string is wrong. I have tried searching and found that .Jet is for access 07?? but this doesnt seem to work too.
i am an amateur at databases (code referred from msdn). I am having trouble understand which should i use for this example too.
access table name: haha
ID (PK) | password
-----------------------
1 | testing
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\BC207\test.accdb");
System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand();
comm.CommandText = "SELECT HAHA(*) FROM password";
comm.CommandType = CommandType.Text;
comm.Connection = conn;
conn.Open();
Object returnValue = comm.ExecuteScalar();
conn.Close();
MessageBox.Show((string)returnValue);
edited: the table's name is password, and the field that i want to get the value is ID.
SQL statement i wrote it as : SELECT ID FROM password
and yes, only one record in only one field in the table as the primary key.
anyway the problem is that the program hangs upon execution on the first line
-> Keyword not supported: 'provider'.
so i figured that I have a wrong connection string..
For Acces databases (.mdb, .accdb, etc...), you want to use OleDbConnection, not SqlConnection (SQL Server), like this:
conn = new System.Data.OleDb.OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\BC207\test.accdb")
Edit: as pointed out, for access OleDbConnection should be used, not SqlConnection...
you can use a much more compact way and also be sure connection is closed and disposed in any possible case even when exceptions are thrown, by using the using statements:
your query text was also, probably wrong as others have suggested...
using (var conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\BC207\test.accdb"))
using (var comm = conn.CreateCommand())
{
comm.CommandText = "SELECT password FROM HAHA";
comm.CommandType = CommandType.Text;
conn.Open();
var returnValue = comm.ExecuteScalar();
MessageBox.Show(returnValue.ToString());
}
Edit: are you sure the table HAHA only contains one row? Because the ExecuteScalar returns only one value, if you want to get 1 column but from many records you could use a DataReader or a DataSet...
comm.CommandText = "SELECT HAHA(*) FROM password";
It´s wrong.
"SELECT password FROM HAHA"
Your SQL statement should be,
SELECT * from HAHA
OR
SELECT [Password] From HAHA
EDIT:
You should change the ConnectionString.

Categories