Could not read values using IDataReader - c#

I want to read data to a list from database.
I tried the following code
public List<T> StoredProcedureForIList<T>(string spName, params IDataParameter[] commandParameters)
{
List<T> list = new List<T>();
T item;
Type listItemType = typeof(T);
item = (T)Activator.CreateInstance(listItemType);
list.Add(item);
using (IDatabaseConnection connection = new DatabaseConnection())
{
IDbCommand cmd = connection.CreateCommandForStoredProcedure(spName);
foreach (SqlParameter par in commandParameters)
{
cmd.Parameters.Add(par);
}
try
{
using (IDataReader reader = cmd.ExecuteReader())
{
while (reader != null && reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
var prop = listItemType.GetProperty(reader.GetName(i));
prop.SetValue(item, reader[i], null);
}
list.Add(item);
}
}
}
catch(Exception ex)
{ }
return list;
}
}
But the problem is that when the for loop starts the reader loses data.
The data reader ResultView value is Enumeration yielded no results.

My guess is that some error occurs during execution of your loop. This technique...
try
{
...
}
catch(Exception ex)
{ }
...ensures that this error is ignored and all you get is an incomplete result. As you have noticed, this makes debugging quite hard. So don't do that.
Thus, the solution is:
remove the try-catch block (i.e., replace try { ... } catch(Exception ex) {} by ...),
run the code again,
note the error that occurs,
if you understand the error
fix it
else
ask again on StackOverflow, in a new question.
And, never, never write catch (Exception ex) {} again. ;-) Do proper error handling, or don't do error handling at all.

The reader won't be dropping rows; the reader is pretty well-tested. Swallowing exceptions won't help. If I had to guess, the problem here is that you are adding the same item over and over. In fact, you add it N+1 times (you add it once at the top even if no rows are returned).
However, can I suggest: just use something like dapper, which does everything above, except a: it gets it right, and b: it is highly optimized (it emits custom IL to avoid constant reflection, and caches that IL). It would be something akin to:
var list = connection.Query<T>(procName, namedArgs,
commandType: CommandType.StoredProcedure).ToList();
where namedArgs would be, to pass in #id and #name, for example:
new {id=123, name="abc"}
i.e.
int id = ...
string name = ...
var list = connection.Query<T>("MyProc", new {id, name},
commandType: CommandType.StoredProcedure).ToList();

Related

LINQ to SQL not creating Transactions

I've been searching everywhere, to try and get over this issue but I just can't figure this out.
I'm trying to make many changes to the DB with one single transaction using LINQ to SQL.
I've created a .dbml that represents the SQL Table, then I use basicaly this code:
foreach (var _doc in _r.Docs)
{
try
{
foreach (var _E in _Es)
{
Entity _newEnt = CreateNewEnt(_EListID, _doc, _fileName, _E);
_db.Etable.InsertOnSubmit(_newEnt);
_ECount++;
if (_ECount % 1000 == 0)
{
_db.SubmitChanges();
}
}
}
catch (Exception ex)
{
throw;
}
}
But when I do a SQL Profiler, the commands are all executed individually. It won't even start an SQL Transaction.
I've tried using TransactionScope (using statement and Complete()) and DbTransaction (BeginTransaction() and Commit()), none of them did anything at all, it just keeps on executing all commands individually, inserting everything like it was looping through all the inserts.
TransactionScope:
using(var _tans = new TransactionScope())
{
foreach (var _doc in _r.Docs)
{
try
{
foreach (var _E in _Es)
{
Entity _newEnt = CreateNewEnt(_EListID, _doc, _fileName, _E);
_db.Etable.InsertOnSubmit(_newEnt);
_ECount++;
if (_ECount % 1000 == 0)
{
_db.SubmitChanges();
}
}
}
catch (Exception ex)
{
throw;
}
}
_trans.Complete();
}
DbTransaction:
_db.Transaction = _db.Connection.BeginTransaction();
foreach (var _doc in _r.Docs)
{
try
{
foreach (var _E in _Es)
{
Entity _newEnt = CreateNewEnt(_EListID, _doc, _fileName, _E);
_db.Etable.InsertOnSubmit(_newEnt);
_ECount++;
if (_ECount % 1000 == 0)
{
_db.SubmitChanges();
}
}
}
catch (Exception ex)
{
throw;
}
}
_db.Transaction.Commit();
I also tried commiting transactions everytime I Submit the changes, but still nothing, just keeps on executing everything individually.
Right now I'm at a loss and wasting time :\
GSerg was right and pointed me to the right direction, Transactions do not mean multiple commands in one go, they just allow to "undo" all that was made inside given transaction if need be. Bulk statements do what I want to do.
You can download a Nuget Package directly from Visual Studio called "Z.LinqToSql.Plus" that helps with this. It extends DataContext from LINQ, and allows to do multiple insertions, updates or deletes in bulks, which means, in one single statement, like this:
foreach (var _doc in _r.Docs)
{
try
{
foreach (var _E in _Es)
{
Entity _newEnt = CreateNewEnt(_EListID, _doc, _fileName, _E);
_dictionary.add(_ECount, _newEnt); //or using a list as well
_ECount++;
if (_ECount % 20000 == 0)
{
_db.BulkInsert(_dictionary.Values); //inserts in bulk, there are also BulkUpdate and BulkDelete
_dictionary = new Dictionary<long, Entity>(); //restarts the dictionary to prepare for the next bulk
}
}
}
catch (Exception ex)
{
throw;
}
}
As in the code, I can even insert 20k entries in seconds. It's a very useful tool!
Thank you to everyone who tried helping! :)

Postgresql query returns NullReferenceException

I'm using Selenium + postgre integration in order to validate correct data on database. After an action on UI then I'm using Npgsql library in order to receive scalar value from cell and then use it for assertion.
Code looks line:
public static string GetCreditAmount(string orderId, string accountNumber)
{
string findCreditQuery = $#"SELECT ""Credit"" FROM accounting.""AccountLines"" al INNER JOIN accounting.""Accounts"" acc ON al.""Account_FK"" = acc.""Id""
WHERE
""OrderId"" = '{orderId}'
AND ""AccountNumber"" = '{accountNumber}'
ORDER BY al.""CreatedDateUtc"" DESC";
using (var connection = new NpgsqlConnection(Configuration.AdminConnectionString))
{
connection.Open();
var transaction = connection.BeginTransaction();
try
{
var account = connection.ExecuteScalar(findCreditQuery).ToString();
return account;
}
catch (NullReferenceException e)
{
Thread.Sleep(3000);
var account = connection.ExecuteScalar(findCreditQuery).ToString();
return account;
}
catch (Exception e)
{
transaction.Rollback();
throw e;
}
}
}
The problem which I'm receiving is NullReferenceException, however results are really random. In one test I'm firing & asserting few times where in like 85% it does not work (Null reference) and from time to time in like 15% it works (test passed). Strange case is that assertion which was fine in one run fails in another one.
I was trying to add static sleeps (Thread.Sleep) in order to give database few extra second for proceeding but all it still fails.
Is there any proper solution which can be used?
If you do this:
object o = null;
string s = o.ToString();
I believe you will get the same error. I believe the issue is your database object is null.
This will probably fix it:
object o = connection.ExecuteScalar(findCreditQuery);
string account = o == null ? null : o.ToString();
Alternatively, you can implement a DbDataReader and use the IsDbNull method. It will be more work but might also be more scalable if you plan to do more than what's currently being done:
string account;
using (NpgsqlCommand cmd = new NpgsqlCommand(findCreditQuery, connection))
{
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
reader.Read();
if (!reader.IsDBNull(0))
account = reader.GetString(0);
}
}

try/catch block not catching an exception

I am having an issue where an exception is not being caught by try/catch block. The issue occurs at command.ExecuteReader(), however it never gets caught. I am running in debug mode and have already tried a few suggested options in regards to the debugger settings with no avail.
I do want to mention that I am using SQLite as my provider, and I can see that it throws an SQLiteException, however the issue remains. Would there be any specific scenario where an exception is not caught? (with exception of StackOverflowException, ThreadAbortedException etc...)
public IEnumerable<dynamic> Query(string sql, params object[] parms)
{
try
{
return QueryCore(sql, parms);
}
catch (Exception ex)
{
throw new DbException(sql, parms, ex);
}
}
private IEnumerable<dynamic> QueryCore(string sql, params object[] parms)
{
using (var connection = CreateConnection())
{
using (var command = CreateCommand(sql, connection, parms))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return reader.ToExpando();
}
}
}
}
}
I also want to add that if I produce a correct query against the database, I get results back, however when I break the query, the exception is thrown, however not caught.
This happens because you are returning the data with the yield keyword.
This makes the data actual data method to run only when it's results are enumerated.
You probably don't want this to happen, especially because if the results are enumerated twice (e.g. two seperate foreach loops) the data will be read twice.
You can do this to make the enumeration to happen immediately and catch any exception:
public IEnumerable<dynamic> Query(string sql, params object[] parms)
{
try
{
return QueryCore(sql, parms).ToArray();
}
catch (Exception ex)
{
throw new DbException(sql, parms, ex);
}
}
Yielding is good for situations where getting an item takes some time, and you don't want to get ALL the items before you can loop through them. So another possible solution, that might be better for the readability of your code (that I assume doesn't need to yield) will be this:
public IEnumerable<dynamic> Query(string sql, params object[] parms)
{
try
{
return QueryCore(sql, parms);
}
catch (Exception ex)
{
throw new DbException(sql, parms, ex);
}
}
private IEnumerable<dynamic> QueryCore(string sql, params object[] parms)
{
using (var connection = CreateConnection())
{
using (var command = CreateCommand(sql, connection, parms))
{
using (var reader = command.ExecuteReader())
{
var results = new List<dynamic>();
while (reader.Read())
{
results.Add(reader.ToExpando());
}
return results;
}
}
}
}

Cant get Exceptions & Dispose() to work in this method

I have the following function which reads from a firebird database. The Function works but does not handle exceptions (Required).
public IEnumerable<DbDataRecord> ExecuteQuery(string Query)
{
var FBC = new FbCommand(Query, DBConnection);
using (FbDataReader DBReader = FBC.ExecuteReader())
{
foreach (DbDataRecord record in DBReader)
yield return record;
}
}
Adding try/catch to this function gives an error regarding yield. I understand why I get the error but any workround I've tried has resulted in DBReader being disposed indirectly via using() too early or Dispose() not being called all. How do I get this code to use Exceptions & Cleanup without having to wrap the method or duplicate DBReader which might contain several thousand record?
Update:
Here is an example of an attempted fix. In this case DBReader is being disposed too early.
public IEnumerable<DbDataRecord> ExecuteQuery(string Query)
{
var FBC = new FbCommand(Query, DBConnection);
FbDataReader DBReader = null;
try
{
using (DBReader = FBC.ExecuteReader());
}
catch (Exception e)
{
Log.ErrorException("Database Execute Reader Exception", e);
throw;
}
foreach (DbDataRecord record in DBReader) <<- DBReader is closed at this stage
yield return record;
}
The code you've got looks fine to me (except I'd use braces round the yield return as well, and change the variable names to fit in with .NET naming conventions :)
The Dispose method will only be called on the reader if:
Accessing MoveNext() or Current in the reader throws an exception
The code using the iterator calls dispose on it
Note that a foreach statement calls Dispose on the iterator automatically, so if you wrote:
foreach (DbDataRecord record in ExecuteQuery())
{
if (someCondition)
{
break;
}
}
then that will call Dispose on the iterator at the end of the block, which will then call Dispose on the FbDataReader. In other words, it should all be working as intended.
If you need to add exception handling within the method, you would need to do something like:
using (FbDataReader DBReader = FBC.ExecuteReader())
{
using (var iterator = DBReader.GetEnumerator())
{
while (true)
{
DbDataRecord record = null;
try
{
if (!iterator.MoveNext())
{
break;
}
record = iterator.Current;
}
catch (FbException e)
{
// Handle however you want to handle it
}
yield return record;
}
}
}
Personally I'd handle the exception at the higher level though...
This line won't work, note the ; at the end, it is the entire scope of the using()
try
{
using (DBReader = FBC.ExecuteReader())
; // this empty statement is the scope of using()
}
The following would be the correct syntax except that you can't yield from a try/catch:
// not working
try
{
using (DBReader = FBC.ExecuteReader())
{
foreach (DbDataRecord record in DBReader)
yield return record;
}
}
catch (Exception e)
{
Log.ErrorException("Database Execute Reader Exception", e);
throw;
}
But you can stay a little closer to your original code:
// untested, ought to work
FbDataReader DBReader = null;
try
{
DBReader = FBC.ExecuteReader();
}
catch (Exception e)
{
Log.ErrorException("Database Execute Reader Exception", e);
throw;
}
using (DBReader)
{
foreach (DbDataRecord record in DBReader) // errors here won't be logged
yield return record;
}
To catch errors from the read loop as well see Jon Skeet's answer.

Workaround for ASP throwing MySQL exception

This is going to take some explaining. I'm new to ASP, having come from PHP. Completely different world. Using the MySql Connecter/Net library, I decided to make a database wrapper which had a fair amount of fetch methods, one being a "FetchColumn()" method which simply takes a string as its parameter and uses the following implementation:
public object FetchColumn(string query)
{
object result = 0;
MySqlCommand cmd = new MySqlCommand(query, this.connection);
bool hasRows = cmd.ExecuteReader().HasRows;
if (!hasRows)
{
return false;
}
MySqlDataReader reader = cmd.ExecuteReader();
int count = 0;
while(reader.HasRows)
{
result = reader.GetValue(count);
count++;
}
return result;
}� return result;
}public object FetchColumn(string query)
What I'm looking for is a way to return false IF and only IF the query attempts to fetch a result which doesn't exist. The problem is that, with my implementation, it throws an error/exception. I need this to "fail gracefully" at run time, so to speak. One thing I should mention is that with this implementation, the application throws an error as soon as the boolean "hasRows" is assigned. Why this is the case, I have no idea.
So, any ideas?
It's hard to say for sure, since you didn't post the exact exception that it's throwing, but I suspect the problem is that you're calling ExecuteReader on a command that is already in use. As the documentation says:
While the MySqlDataReader is in use, the associated MySqlConnection is busy serving the MySqlDataReader. While in this state, no other operations can be performed on the MySqlConnection other than closing it. This is the case until the MySqlDataReader.Close method of the MySqlDataReader is called.
You're calling cmd.ExecuteReader() to check to see if there are rows, and then you're calling ExecuteReader() again to get data from the rows. Not only does this not work because it violates the conditions set out above, it would be horribly inefficient if it did work, because it would require two trips to the database.
Following the example shown in the document I linked, I'd say what you want is something like:
public object FetchColumn(string query)
{
MySqlCommand cmd = new MySqlCommand(query, this.connection);
MySqlDataReader reader = cmd.ExecuteReader();
try
{
bool gotValue = false;
while (reader.Read())
{
// do whatever you're doing to return a value
gotValue = true;
}
if (gotValue)
{
// here, return whatever value you computed
}
else
{
return false;
}
}
finally
{
reader.Close();
}
}
I'm not sure what you're trying to compute with the HasRows and the count, etc., but this should get you pointed in the right direction.
you need to surround the error throwing code with a try clause
try {
//The error throwing Code
}
catch (exception e)
{
//Error was encountered
return false
}
If the error throwing code throws and error the catch statement will execute, if no error is thrown then the catch statement is ignored
First of all do a try and catch
try
{
//code
}
catch (Exception exp)
{
//show exp as message
}
And the possible reason of your error is that your mysql query has errors in it.
try executing your query directly in your mysql query browser and you'll get your answer.
If its working fine then double check your connection string if its correct.
NOTE:mark as answer if it solves your issue

Categories