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);
}
}
Related
Whats the Perfered Method to handle Errors in a SQL Stored Procedure when Using Entity Framework.
I have a chunk of code that uses a database context and EF to call a stored procedure. If everything is perfect, the stored procedure returns a list of keys to tell me which records were modified. If something goes wrong in the stored procedure, the transaction rolls back and I believe the response type is a string and causes this error:
The data reader has more than one field. Multiple fields are not valid for EDM primitive or enumeration types.
After doing so digging I noticed that the SQL developer had put "PRINT: ERROR MESSAGE HERE" statement to pass back a message, However the current call does not allow for this,
Here is how the call is currently being made:
var partIdsCreated = context.Database.SqlQuery<int>("EXEC My_SP #FilePath, #FileName", args).ToList();
The Current Code is expecting a list of Int and if a string is Returned it Errors out with the Error Message listed above, So what is the best way to handle errors coming back from a Stored Procedure in a Transaction Using Entity Framework 6?
Below I have provided two similar ways to handle messages returned by SQL Server. As noted in the comments, both involve the usage of the InfoMessage event on the connection.
To answer your question, I don't really know of a preferred way to do handle PRINT statements as errors, but I am also not really sure of another way to handle the output.
Solution 1: Catch Exception
public class DataLoader_01
{
public int LoadData()
{
_infoMessage = null;
using (var context = new ApplicationDbContext(#"Server=localhost\SQLEXPRESS;Database=StackOverflow;Trusted_Connection=True;"))
{
var sqlConnection = (SqlConnection)context.Database.Connection;
sqlConnection.InfoMessage += InfoMessage;
try
{
var t = context.Database.SqlQuery<int>("EXEC ErrorMessageHandling", new object[] {});
return t.First();
}
catch (EntityCommandExecutionException e)
{
if (string.IsNullOrEmpty(_infoMessage))
{
//do some error handling specific to your application
throw new ApplicationSpecificException(_infoMessage);
}
throw;
}
}
}
private void InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
_infoMessage = e.Message;
}
private string _infoMessage;
}
Solution 2: Check Field Count
public class DataLoader_02
{
public int LoadData()
{
_infoMessage = null;
using (var context = new ApplicationDbContext(#"Server=localhost\SQLEXPRESS;Database=StackOverflow;Trusted_Connection=True;"))
{
var sqlConnection = (SqlConnection)context.Database.Connection;
sqlConnection.InfoMessage += InfoMessage;
var cmd = context.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[SomeProc]";
try
{
context.Database.Connection.Open();
var reader = cmd.ExecuteReader();
if (reader.FieldCount == 0)
{
throw new ApplicationSpecificException(_infoMessage);
}
var result = ((IObjectContextAdapter)context).ObjectContext.Translate<int>(reader);
return result.First();
}
finally
{
context.Database.Connection.Close();
}
}
}
private void InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
_infoMessage = e.Message;
}
private string _infoMessage;
}
I am coding a Sql-Server-ce application in C#.
Recently I have been converting my code to use using statements, as they are much cleaner. In my code I have a GetLastInsertedID function which is very simple - it returns the last inserted ID. The working version is as follows:
public static int GetLastInsertedID()
{
int key = 0;
try
{
SqlCeCommand cmd = new SqlCeCommand("SELECT CONVERT(int, ##IDENTITY)", DbConnection.ceConnection);
key = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
MessageBox.Show("Could not get last inserted ID. " + ex.Message);
key = 0;
}
return key;
}
Below is the code that does NOT work once I wrap it in using statements:
public static int GetLastInsertedID()
{
int key = 0;
try
{
using (SqlCeConnection conn = new SqlCeConnection(DbConnection.compact))
{
conn.Open();
using (SqlCeCommand cmd = new SqlCeCommand("SELECT CONVERT(int, ##IDENTITY)", conn))
key = (int)cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
MessageBox.Show("Could not get last inserted ID. " + ex.Message);
key = 0;
}
return key;
}
The error that I'm getting is specified cast is not valid. Although this error is usually self-explanatory, I cannot see why I would be getting it inside the second block of code, but not the first. This error occurs on the line key = (int)cmd.ExecuteScalar();.
What am I doing wrong with the second block of code?
From the ##IDENTITY documentation:
##IDENTITY and SCOPE_IDENTITY will return the last identity value generated in any table in the current session.
I think your change now starts a new session for each using statement. Therefore ##IDENTITY is null.
First of all, ##Identity will return any last generated ID from anywhere in SQL Server. Most probably you need to use SCOPE_IDENTITY() instead.
This shows your actual problem and design issue - you need to keep Connection and Command separate. Connection embeds transaction and though SCOPE_IDENTITY() will work until connection is closed; Command can be created, used and disposed.
So you need method which accept connection and use it to obtain identity - something like this (didn't check it but think idea should be clear):
public static int GetLastInsertedID(DbConnection connection)
{
try
{
string query = "SELECT CONVERT(int, SCOPE_IDENTITY())";
using (SqlCeCommand cmd = new SqlCeCommand(query, conn)) {
return (int)cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
MessageBox.Show("Could not get last inserted ID. " + ex.Message);
return 0;
}
}
For working with connection you can create helper method like this:
public static SqlCeConnection OpenDefaultConnection()
{
SqlCeConnection conn = new SqlCeConnection(DbConnection.compact);
conn.Open();
return conn;
}
And use it like this:
...
using (SqlCeConnection conn = OpenDefaultConnection()) {
//... do smth
int id = GetLastInsertedID(conn);
//... do smth
}
...
in my opinion, the reason that it doesn't work is not related to the using statement.
If you use a static class to do the operation of connecting database, like DBHelper. The problem will be caused by that you close the connection of database before you execute the select ##identity and when you execute select ##identity, you open it again. This executing sequence will cause that the return result of select ##identity is NULL. That is, you can not use DBHelper.xxx() twice for getting the automated ID, because every time you call DBHelper.xxx(), the process of the opening database and the closing database will be done.
I have a solution but it maybe not the best one. Instead of using select ##identity, you can use select count(*) from xxx to get the same result.
Hope that it can help you
I am trying to update a record in an access file (.accdb). I am trying to use the .net OleDbCommand and OleDbParameters. I am also trying to use a generic model and store all of the commands and parameters in the System.Data.Common abstract equivalents so that I can easily switch over to SQL Server (which I do plan to do)
So here is the actual command being used
EDIT 2/2/2013 - 9:10pm
the command.ExecuteNonQuery is inside the method named ExecuteNonQuery()
the connectionString and command are defined in the DataAccess class constructor
public class DataAccess
{
private string connectionString;
private DbConnection connection;
private DbCommand command;
private DbDataReader reader;
private DataTable data;
public DataAccess()
{
connectionString = ConfigurationSettings.AppSettings["ConnectionString"];
switch (ConfigurationSettings.AppSettings["DataBaseType"])
{
case "oledb":
connection = new OleDbConnection(connectionString);
command = new OleDbCommand(string.Empty, (OleDbConnection)connection);
break;
case "SQL":
connection = new SqlConnection(connectionString);
command = new SqlCommand(string.Empty, (SqlConnection)connection);
break;
default:
break;
}
}
public void ExecuteNonQuery(string SQL, params DbParameter[] parameters)
{
command.CommandType = CommandType.Text;
command.CommandText = SQL;
command.Parameters.AddRange(parameters);
try
{
command.Connection.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
command.Connection.Close();
}
}
catch (Exception ex)
{
throw ex;
}
}
public DbParameter NewParameter(string name, object value)
{
DbParameter param;
switch (ConfigurationSettings.AppSettings["DataBaseType"])
{
case "oledb":
param = new OleDbParameter(name, value);
break;
case "SQL":
param = new SqlParameter(name, value);
break;
default:
param = null;
break;
}
return param;
}
These are the properties in the App.Config File
<add key="DataBaseType" value="oledb"/>
<add key="ConnectionString" value="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=data.accdb"/>
Now the problem is when using parameters in an update statement, the update never happens and also never throws an error. Here is the code for it.
EDIT 2/2/2013 - 9:10pm
the function DataAccess.NewParameter is in the first code block
DALayer.ExecuteNonQuery("UPDATE TileTypes SET Title = #Title, Picture = #Picture, Color = #Color WHERE ID = #ID",
DALayer.NewParameter("#Title", titleTextBox.Text.Trim()),
DALayer.NewParameter("#Picture", typePictureBox.ImageLocation),
DALayer.NewParameter("#Color", colorButton.BackColor.ToArgb()),
DALayer.NewParameter("#ID", id));
I have copied the query into access and replaced all of the parameter names with the actual data being passed, this works fine. I have tried replacing all of the parameters in the SQL text to the ? character to no effect. I have tried enclosing all of the table and column names in brackets [] also to no effect.
ID is an AutoNumber field
Title is a Text field
Picture is a Text field
Color is a Long Integer field
This is some example data that was copied directly from the parameters in the watch window for Visual Studio:
"Edit" (title)
-1 (color)
"data\images\Edit_000000.jpg" (picture)
740 (id)
That ID does exist in the database and was unchanged after the query executed.
EDIT 2/2/2013 - 9:10pm
I am not sure how to check which database is actually being updated, the only thing I could think of was that using the same connection string and connection object I did an insert statement with the same ExecuteNonquery method and it worked in the database I was viewing. And the update statement works just fine like this (without parameters):
DALayer.ExecuteNonQuery("UPDATE TileTypes SET Title = '" + titleTextBox.Text +
"', Color = " + colorButton.BackColor.ToArgb() + ", Picture = '" +
imageLocation + "' WHERE ID = " + id);
EDIT 2/2/2013 - 9:41pm
I have used everything.exe to search my computer for all of the data.accdb files on my computer, I have found no actual .accdb files besides the original but I did find these .lnk files, I do not believe they could have altered this process but I will mention it anyway
data.accdb.LNK
What you are trying to do is something I too have done in the past, but allowed to connect to OleDB (such as Access, Visual FoxPro, etc), SQL-Server, SyBase SQLAnywhere and maybe my implementation might help you. First, each of the elements you would use for connecting work on a common interface, such as IDbConnection, IDbCommand, IDbParameter, etc.
The following I'm posting is a small segment of how I originally structured such multi-database connection type. I've stripped a bunch out and not actually tested this stripped version, but it SHOULD be a good baseline for you to run with.
The premise is a baseline "MyConnection" to almost be like an abstract, but has properties and some "common" methods that would exist under EITHER subclassed definition. From this, each of the functions and parameter types are based on the "I"nterface, not a specific. However, each of the derived will create its OWN proper type. This removes the need to "Case" everything. Hope this helps you along with your Data Access Layer development.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
// for OleDB (Access, VFP, etc)
using System.Data.OleDb;
// for SQL-Server
using System.Data.SqlClient;
namespace DataMgmt
{
public class MyConnection
{
// no matter the connection to server, it will require some "handle"
// that is of type "IDbConnection"
protected IDbConnection sqlConnectionHandle;
// when querying, ANY query could have an exception that needs to have
// possible further review for handling
public Exception LastException
{ get; protected set; }
// When calling an execute command (select, insert, update, delete),
// they all can return how many rows affected
public int RowsAffectedByQuery
{ get; protected set; }
// different databases could have different connection strings. Make
// virtual and throw exception so sub-classed must return proper formatted.
public virtual string GetConnectionString()
{ throw new Exception("GetConnectionString() method must be overridden."); }
// each has its own "IDbConnection" type too
protected virtual IDbConnection SQLConnectionHandle()
{ return sqlConnectionHandle; }
public virtual IDbCommand GetSQLDbCommand()
{ throw new Exception("GetSQLDbCommand() method must be overridden."); }
// generic routine to get a data parameter...
public virtual IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ throw new Exception("AddDbParmSpecificValue() method must be overwritten per specific connection."); }
// generic "Connection" since they are all based on IDbCommand...
public override bool SQLConnect()
{
// pre-blank exception in case remnant from previous activity
LastException = null;
if (sqlConnectionHandle.State != System.Data.ConnectionState.Open)
try
{
// if not open, always make sure we get updated connection string
// if ever changed by some other "unknown" condition...
sqlConnectionHandle.ConnectionString = GetConnectionString();
sqlConnectionHandle.Open();
}
catch (Exception ex)
{
// Preserve in generic sqlException" property for analysis OUTSIDE this function
LastException = ex;
}
// if NOT connected, display message to user and set error code and exception
if (sqlConnectionHandle.State != System.Data.ConnectionState.Open)
LastException = new Exception("Unable to open database connection.");
// return if it IS successful at opening the connection (or was already open)
return sqlConnectionHandle.State == System.Data.ConnectionState.Open;
}
// likewise disconnect could be common
public void SQLDisconnect()
{
if (sqlConnectionHandle != null)
if (sqlConnectionHandle.State == ConnectionState.Open)
sqlConnectionHandle.Close();
}
public bool SqlExecNonQuery( IDbCommand SQLCmd, DataTable oTbl)
{
// pre-clear exception
LastException = null;
// fill the table...
SQLConnect();
try
{
RowsAffectedByQuery = SQLCmd.ExecuteNonQuery();
}
catch (Exception e)
{
LastException = e;
throw e;
}
finally
{
SQLDisconnect();
}
// Its all ok if no exception error
return LastException == null;
}
}
// Now, build your connection manager per specific type
public class MyAccessConnection : MyConnection
{
public MyAccessConnection()
{ sqlConnectionHandle = new OleDbConnection(); }
public override string GetConnectionString()
{ return "Your Connection String from AppSettings.. any changes if OleDb vs SQL"; }
public override IDbCommand GetSQLDbCommand()
{ return new OleDbCommand( "", (OleDbConnection)sqlConnectionHandle ); }
public override IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ return new OleDbParameter( ParmName, UnknownValue ); }
}
public class MySQLConnection : MyConnection
{
public MySQLConnection()
{ sqlConnectionHandle = new SqlConnection(); }
public override string GetConnectionString()
{ return "Your Connection String from AppSettings... any alterations needed??? "; }
public override IDbCommand GetSQLDbCommand()
{ return new SqlCommand ("", (SqlConnection)sqlConnectionHandle); }
public override IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ return new SqlParameter(ParmName, UnknownValue); }
}
// Now to implement... pick one... Access or SQL-Server for derivation...
public class MyDataLayer : MyAccessConnection
{
public void SomeSQLCall()
{
IDbCommand sqlcmd = GetSQLDbCommand();
sqlcmd.CommandText = "UPDATE TileTypes SET Title = #Title, "
+ "Picture = #Picture, "
+ "Color = #Color "
+ "WHERE ID = #ID";
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#Title", titleTextBox.Text.Trim() ));
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#Picture", typePictureBox.ImageLocation) );
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#Color", colorButton.BackColor.ToArgb()) );
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#ID", id));
if( SqlExecNonQuery(sqlcmd))
// Good to go
DoSomethingWithTheData;
else
// Notify of whatever error thrown....
}
}
}
So.. as you can see, my last class specifically is derived from EITHER Access OR SQL. Then, I can create my methods to get data, call updates, whatever. Get a SQL Command (which returns proper type and automatically is attached to its corresponding "Connection Handle" object, prepare the text, add your parameters, execute it.
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();
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