C# ExecuteReader has rows but result view initially with question marks - c#

ExecuteReader has rows but initially when i hover and look at result view it has question marks for all the rows. Then when i go back in a second time to hover it says enumeration yielded no results. the HasRows is true however. I'm also getting my output parameters fine, but not the result set from the select statement. I'm executing a sql server stored proc. the SP executes fine in management studio. And again i am getting the output parms, just not the result set.
internal static CrossWalk Create(string senderId, string ediType)
{
var connection = ConfigurationManager.ConnectionStrings["caeCustom"];
DbCommand cmd = new SqlCommand();
cmd.CommandText = "emb_edi_xwalk_select";
cmd.CommandType = CommandType.StoredProcedure;
cmd.AddParameter("#pSENDER_ID", senderId);
cmd.AddParameter("#pMAPPING_TYPE", ediType);
var delegateId = new SqlParameter
{
ParameterName = "#pDELEGATE_ID",
SqlDbType = SqlDbType.Int,
Direction = ParameterDirection.Output
};
cmd.Parameters.Add(delegateId);
var crossWalk = new CrossWalk();
var dbFactory = DbProviderFactories.GetFactory(connection.ProviderName);
using(var sqlConnection =
dbFactory.CreateConnection(connection.ConnectionString))
{
cmd.Connection = sqlConnection;
using (var sqlReader = cmd.ExecuteReader())
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
//Mapping of AAA values will be AAA03~internal_value -->
loop~external_value
//i.e. AAA03~1008 --> 2010EA~51
string key;
string value;
if (sqlReader["element"].ToString() == "AAA03")
{
key = string.Join("~",
sqlReader["element"].ToString(), sqlReader["internal_value"].ToString());
value = string.Join("~", sqlReader["loop"].ToString(),
sqlReader["external_value"].ToString());
}
else
//Normal xwalk mapping will be loop+element~external_value
--> internal_value
//i.e. 2010ANM101~X3 --> 3
{
key = string.Join("~", sqlReader["loop"] +
sqlReader["element"].ToString(), sqlReader["external_value"].ToString());
value = sqlReader["internal_value"].ToString();
}
crossWalk._lookups.Add(key, value);
}
}
sqlReader.Close();
}
crossWalk.DelegateId =
Convert.ToInt32(cmd.Parameters["#pDELEGATE_ID"].Value);
}
return crossWalk;
}

Related

If the SELECT SQL Server value is null, the query takes 5 minutes C #

I have a very silly problem. I am doing a select, and I want that when the value comes null, return an empty string. When there is value in sql query, the query occurs all ok, but if there is nothing in the query, I have to give a sqlCommand.CommandTimeout greater than 300, and yet sometimes gives timeout. Have a solution for this?
public string TesteMetodo(string codPess)
{
var vp = new Classe.validaPessoa();
string _connection = vp.conString();
string query = String.Format("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = {0}", codPess);
try
{
using (var conn = new SqlConnection(_connection))
{
conn.Open();
using (var cmd = new SqlCommand(query, conn))
{
SqlDataReader dr = cmd.ExecuteReader();
if(dr.HasRows)
return "";
return codPess;
}
}
}
You should probably validate in the UI and pass an integer.
You can combine the usings to a single block. A bit easier to read with fewer indents.
Always use parameters to make the query easier to write and avoid Sql Injection. I had to guess at the SqlDbType so, check your database for the actual type.
Don't open the connection until directly before the .Execute. Since you are only retrieving a single value you can use .ExecuteScalar. .ExecuteScalar returns an Object so must be converted to int.
public string TesteMetodo(string codPess)
{
int codPessNum = 0;
if (!Int32.TryParse(codPess, out codPessNum))
return "codPess is not a number";
var vp = new Classe.validaPessoa();
try
{
using (var conn = new SqlConnection(vp.conString))
using (var cmd = new SqlCommand("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = #cod_pess", conn))
{
cmd.Parameters.Add("#cod_pess", SqlDbType.Int).Value = codPessNum;
conn.Open();
int count = (int)cmd.ExecuteScalar();
if (count > 0)
return "";
return codPess;
}
}
catch (Exception ex)
{
return ex.Message;
}
}

SQLite keeps locking my database when doing SELECT + UPDATE (C#)

I am trying to doing this:
Read a row from an SQLite db (in GetRuleByID() method)
Update the same row that I just read during (1) (See UpdateStatusForRuleID() method)
However my problem is that SQLite locks the database after the SELECT in GetRuleByID() so that update in UpdateStatusForRuleID() is only successful when called the first time.
I have tried enabling Write-Ahead-Logging in SQLite as well as PRAGMA read_uncommitted=1 in order to avoid SQLite locking the database for the SELECT, but this does not appear to work.
This should be simple but I have so far spent a complete night trying to solve this... Please help !
private static MicroRuleEngine.Rule GetRuleByID(int ruleID, SQLiteConnection connection, out Dictionary<string, string> dict)
{
dict = new Dictionary<string, string>();
string sql = String.Format("select * from rules WHERE ID = {0} ", ruleID.ToString());
SQLiteCommand command = new SQLiteCommand(sql, connection);
SQLiteDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
// Convert row into a dictionary
for (int lp = 0; lp < reader.FieldCount; lp++)
{
dict.Add(reader.GetName(lp), reader.GetValue(lp) as string);
}
string json = dict["fulljson"];
MicroRuleEngine.Rule r = Newtonsoft.Json.JsonConvert.DeserializeObject<MicroRuleEngine.Rule>(json);
//command.Dispose();
return r;
}
}
internal static void UpdateStatusForRuleID(SQLConnectionManager DBMANAGER, int ruleID, bool status)
{
Dictionary<string, string> dict = null;
string dbVal = (status) ? "1" : "0";
MicroRuleEngine.Rule r = null;
string newJSON = null;
using (SQLiteConnection connection = DBMANAGER.CreateConnection())
{
r = GetRuleByID(ruleID, connection, out dict);
r.Active = (status);
newJSON = Newtonsoft.Json.JsonConvert.SerializeObject(r);
Thread.Sleep(1000);
string sql = "UPDATE rules SET active = #a, fulljson=#j WHERE ID = #i";
using (var command = new SQLiteCommand(sql, connection))
{
command.Parameters.Add(new SQLiteParameter("#a", dbVal));
command.Parameters.Add(new SQLiteParameter("#i", ruleID));
command.Parameters.Add(new SQLiteParameter("#j", newJSON));
command.ExecuteNonQuery(); // Database is locked here ???
}
connection.Close();
}
}
"Database is locked" means that some other connection (in the same or some other process) still has an active transaction.
You don't need multiple connections (unless you are using multiple threads); just use a single connection object for all database accesses.
Ensure that all command, reader, and transaction objects (and connections, if you decide to use temporary ones) are properly cleaned up, by using using:
using (var command = new SQLiteCommand(sql, connection))
using (var reader = command.ExecuteReader())
{
if (reader.HasRows)
...
}
Apparently, the code below works. I basically dropped the GetRuleByID() method (but then I had to re-write 4 other methods)
Thanks to all who provided input.
internal static void UpdateStatusForRuleID(SQLConnectionManager DBMANAGER, int ruleID, bool status)
{
string dbVal = (status) ? "1" : "0";
MicroRuleEngine.Rule r = null;
string newJSON = null;
using (SQLiteConnection conn = DBMANAGER.CreateConnection())
{
string sql = String.Format("select * from rules WHERE ID = {0} ", ruleID.ToString());
using (var command = new SQLiteCommand(sql, conn))
using (var reader = command.ExecuteReader())
{
if (reader.HasRows)
{
reader.Read();
string json = reader["fulljson"].ToString();
r = Newtonsoft.Json.JsonConvert.DeserializeObject<MicroRuleEngine.Rule>(json);
r.Active = (status);
newJSON = Newtonsoft.Json.JsonConvert.SerializeObject(r);
string sql2 = "UPDATE rules SET active = #a, fulljson=#j WHERE ID = #i";
using (var command2 = new SQLiteCommand(sql2, conn))
{
command2.Parameters.Add(new SQLiteParameter("#a", dbVal));
command2.Parameters.Add(new SQLiteParameter("#i", ruleID));
command2.Parameters.Add(new SQLiteParameter("#j", newJSON));
command2.ExecuteNonQuery();
}
}
}
}
}

Using IEnumerable<IDataRecord> to return data

I am trying to return data using IEnumerable with given fields, where I am calling the the method I want to reference the data with given field name and return that.
Example, here is the function
public IEnumerable<IDataRecord> GetSomeData(string fields, string table, string where = null, int count = 0)
{
string sql = "SELECT #Fields FROM #Table WHERE #Where";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#Fields", SqlDbType.NVarChar, 255).Value = where;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
Calling:
IEnumerable<IDataRecord> data = bw.GetSomeData("StaffCode, Perms", "BW_Staff", "StaffCode = 'KAA'");
What must I do to return the data this way or what way ?
string staffCode = data["StaffCode"].ToString();
string perms = data["Perms"].ToString();
Thanks for any help
your data variable is a collection of rows. You need to iterate over the collection to do something interesting with each row.
foreach (var row in data)
{
string staffCode = row["StaffCode"].ToString();
string perms = row["Perms"].ToString();
}
Update:
Based on your comment that you only expect GetSomeData(...) to return a single row, I'd suggest 1 of two things.
Change the signature of GetSomeData to return an IDataRecord. and remove "yield" from the implementation.
public IDataRecord GetSomeData(string fields, string table, string where = null, int count = 0)
{
string sql = "SELECT #Fields FROM #Table WHERE #Where";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#Fields", SqlDbType.NVarChar, 255).Value = where;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
return (IDataRecord)rdr;
}
}
}
}
}
Or
var row = data.FirstOrDefault();
if (row != null)
{
string staffCode = row["StaffCode"].ToString();
string perms = row["Perms"].ToString();
}
Remarks:
Your implementation of GetSomeData is incomplete. You are not even using several of the parameters, most importantly the fields parameter. And conceptually in SQL you can't parameterize which fields get returned or which table gets used (etc.), but rather you need to construct a dynamic query and execute it.
Update 2
Here is an implementation of GetSomeData that constructs a proper query (in C# 6, let me know if you need it in an earlier version).
public IEnumerable<IDataRecord> GetSomeData(IEnumerable<string> fields, string table, string where = null, int count = 0)
{
var predicate = string.IsNullOrWhiteSpace(where) ? "" : " WHERE " + where;
string sql = $"SELECT { string.Join(",", fields) } FROM {table} {predicate}";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
And here is how you would use it.
IEnumerable<IDataRecord> data = bw.GetSomeData(new[] { "StaffCode", "Perms" }, "BW_Staff", "StaffCode = 'KAA'");
You can either enumerate it or call .FirstOrDefault, it's your choice. Each time you call GetSomeData, it will run the query.
Update 3
GetSomeData implemented with earlier versions of C#
public IEnumerable<IDataRecord> GetSomeData(IEnumerable<string> fields, string table, string where = null, int count = 0)
{
var predicate = string.IsNullOrEmpty(where) ? "" : " WHERE " + where;
string sql = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", fields), table, predicate);
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}

ADO.NET ExecuteReader Returns No Results

I'm updating some old legacy code and I ran into a problem with the
SqlCommand.ExecuteReader() method. The problem is that it's not returning any
results. However, using SqlDataAdapter.Fill(), I get results back from the
database. What am I doing wrong? How can I get results back using the data
reader?
var connectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString();
using (var sqlConnection = new SqlConnection(connectionString))
{
using (var sqlCommand = new SqlCommand())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = "SELECT * FROM MyTable WHERE ID = 1";
sqlConnection.Open();
// This code works.
//var dataTable = new DataTable();
//using (var sqlDataAdapter = new SqlDataAdapter(sqlCommand))
//{
// sqlDataAdapter.Fill(dataTable);
//}
// This code is not working.
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
// This fails because the data reader has no results.
var id = sqlDataReader.GetInt32(0);
}
}
}
}
Could it be that there is no Int32 in your results ?
var id = sqlDataReader.GetInt32(0); // <-- this might not be an Int32
Either try:
var id = sqlDataReader.GetValue(0);
Or cast to the correct type (BIGINT for example is Int64), not sure without seeing your data.
Try this..
var id = 0;
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
id = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("ColName"));
}
}
I have moved the variable outside of the reader code or the variable will only be accessible inside that scope. I would avoid specifying the ordinal in the code, in case someone altered the columns in the DB.
Also, specify the columns in the SQL statement... SELECT ColName FROM ... and use params in the query
If you got to that line then it has results
Does not mean the value is not null
And you should not use a SELECT *
If may have a problem with an implicit cast
Try Int32
try
{
if(sqlDataReader.IsDBNull(0))
{
// deal with null
}
else
{
Int32 id = sqlDataReader.GetInt32(0);
}
}
catch (SQLexception Ex)
{
Debug.WriteLine(Ex.message);
}
var connectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString();
using (var sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
string sql = "SELECT * FROM MyTable WHERE ID = 1";
using (var sqlCommand = new SqlCommand(sql, sqlConnection))
{
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
// This fails because the data reader has no results.
var id = sqlDataReader.GetInt32(0);
}
}
}
}

How to get the primary key of a table in sql server 2008

I have the following code which should be able to get the primary key in a table
public List<string> GetPrimaryKeysForTable(string tableName)
{
List<String> retVal = new List<string>();
SqlCommand command = connector.GetCommand("sp_pkeys");
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#table_name", typeof(SqlChars)).Value = tableName;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
retVal.Add(reader[3].ToString());
}
return retVal;
}
I have a table called Users in my database. When I pass Users in as my parameter, the reader returns no results. Any idea why this might be failing to return my primary keys?
Try this instead:
command.Parameters.Add("#table_name", SqlDbType.NVarChar).Value = tableName;
It looks like you have an issue with your usage of .AddWithValue() which may be causing your problem. See the fix below:
public List<string> GetPrimaryKeysForTable(string tableName)
{
List<string> retVal = new List<string>();
SqlCommand command = connector.GetCommand("sp_pkeys");
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#table_name", tableName);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
retVal.Add(reader[3].ToString());
}
return retVal;
}
In your example you are attempting to add the #table_name as a Type rather than a string.
Any chance it needs to be qualified with the schema? Something like:
command.Parameters.AddWithValue("#table_name", typeof(SqlChars)).Value = "dbo." + tableName;
or:
command.Parameters.AddWithValue("#schema", "dbo");
Or is there some parm you need to add to tell it the database inside the server?
You can simply use as below, would you please try it out:
command.Parameters.AddWithValue("#table_name", ("dbo." + tableName));
The stored procedure 'sp_pkeys' takes three parameters:
command.Parameters.Add("#table_name", SqlDbType.NVarChar).Value = tableName;
command.Parameters.Add("#table_owner", SqlDbType.NVarChar).Value = tableOwner;
command.Parameters.Add("#table_qualifier", SqlDbType.NVarChar).Value = tableQualifier;
It works with just #table_name but could try passing all three to see if it makes a difference.
Question: Does your table have any keys defined?
I have run the slightly modified code below against severa tables in a test DB of my own and it works as expected:
static class Program
{
static void Main(string[] args)
{
var connStr = new SqlConnectionStringBuilder
{
DataSource = "localhost",
InitialCatalog = "RichTest",
IntegratedSecurity = true
};
using (var conn = new SqlConnection(connStr.ToString()))
{
conn.Open();
var parents = GetPrimaryKeysForTable(conn, "People");
Console.WriteLine("Parent Keys:");
foreach (var p in parents)
{
Console.WriteLine(" {0}", p);
}
}
}
static IList<string> GetPrimaryKeysForTable(SqlConnection conn, string tableName)
{
if (conn == null) throw new ArgumentNullException("Value is null", "conn");
if (string.IsNullOrWhiteSpace(tableName)) throw new ArgumentNullException("Value is null or emtpy", "tableName");
List<String> retVal = new List<string>();
using (var command = new SqlCommand
{
Connection = conn,
CommandText = "sp_pkeys",
CommandType = CommandType.StoredProcedure
})
{
command.Parameters.AddWithValue("#table_name", typeof(SqlChars)).Value = tableName;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
retVal.Add(reader["COLUMN_NAME"].ToString());
}
}
return retVal;
}
}

Categories