I am trying to set timeout for a dbcommand, and test it that is why timeout is set to 1.
This is the code I am using but timeout never fires, am I doing something wrong?
NOTE: DbConnection is used because this code is an extract from a generic code used not only for db2 so db2connection is not an option.
String lProviderFactory = "System.Data.OleDb";
String lStrConexion = "Provider=IBMDADB2;Database=PYRAMID;Hostname=192.9.200.13;Protocol=TCPIP; Port=50000;Uid=db2admin;Pwd=xxx;";
String lQuery = "SLOW SELECT";
var lDbFactory = DbProviderFactories.GetFactory(lProviderFactory);
DbConnection mConexion = lDbFactory.CreateConnection();
mConexion.ConnectionString = lStrConexion;
mConexion.Open();
try
{
DbCommand lComando = mConexion.CreateCommand();
lComando.CommandText = lQuery;
lComando.CommandTimeout = 1;
DbDataAdapter lAdapter = lDbFactory.CreateDataAdapter();
lAdapter.SelectCommand = lComando;
DataSet lDs = new DataSet();
lAdapter.Fill(lDs);
}
catch(Exception ex)
{
Console.WriteLine("EXCEPCION :" + ex.Message); //Timeout should fall in here
}
finally
{
mConexion.Close();
}
Thanks!
Related
This is a c# method that invokes SAP BAPI.
public Message ReleaseBapi(string orderNumber)
{
Message msg = new Message();
DataTable dt = new DataTable();
_ecc = ERPRfcDestination.InitialiseDestination();
try
{
IRfcFunction api = _ecc.Repository.CreateFunction("BAPI_PRODORD_RELEASE");
IRfcTable orderNumTable = api.GetTable("ORDERS");
orderNumTable.Insert();
IRfcStructure ItemData = orderNumTable.CurrentRow;
orderNumber = orderNumber.PadLeft(12,'0');
ItemData.SetValue("ORDER_NUMBER", orderNumber);
api.SetValue("ORDERS", orderNumTable);
BeginContext();
api.Invoke(_ecc);
//EndContext();
IRfcTable detReturnTable = api.GetTable("DETAIL_RETURN");//On this line I am getting RfcInvalidStateException
IRFCToDatatable convertToDT = new IRFCToDatatable();
dt = convertToDT.ToDataTable(detReturnTable, dt);
if (dt.Rows.Count > 0)
{
msg.Msg = "Order number " + orderNumber + " released";
msg.MsgType = "S";
}
else { RollbackAPI(); }
}
catch (Exception ex)
{
msg.MsgType = "D";
msg.Msg = ex.Message;
RollbackAPI();
}
finally
{
EndContext();
}
return msg;
}
I checked every other instances where similar line of code is written and on debugging I found that it works as expected. Above is the only place where I am getting this error although I was able to invoke the Rfc method.
I created a service in windows Worker service that connects to the database at regular intervals and sends the first newest row in the table to the API
But how to make the service send the same row only once and wait until the next new one appears.
ID cannot have the same value, is it possible to create a condition when dbResult[0] (id) of the already sent row != dbResult[0] can be sent ?
My part of code:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
string connectionString = "User=SYSDBA;" +
"Password=masterkey;" +
"Database=test.DTB;" +
"DataSource=localhost;" +
"Port:3050";
FbConnection mConnection = new FbConnection(connectionString);
mConnection.Open();
FbTransaction mTransaction = mConnection.BeginTransaction();
string SQLCommandText = "select first 1 * from TABLE where NAME = 449 order by DATE desc ";
FbCommand mCommand = new FbCommand(SQLCommandText, mConnection, mTransaction);
FbDataReader mReader = mCommand.ExecuteReader();
if (mReader.Read())
{
var values = new object[mReader.FieldCount];
{
mReader.GetValues(values);
var dbResult = values.Distinct().ToArray();
var dbResults = (string.Join("|", dbResult));
var result = new
{
ID = dbResult[0],
NAME = dbResult[1],
DATE = dbResult[2],
};
var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(result);
}
}
}
catch (Exception ex)
{
Log.Fatal(ex, "Problem reading the database.");
}
await Task.Delay(10000, stoppingToken);
}
}
}
UPDATE after get nice clue from Barr J
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
string connectionString = "User=SYSDBA;" +
"Password=masterkey;" +
"Database=test.DTB;" +
"DataSource=localhost;" +
"Port:3050";
FbConnection mConnection = new FbConnection(connectionString);
mConnection.Open();
FbTransaction mTransaction = mConnection.BeginTransaction();
string SQLCommandText = "select NAME, DATE from TABLE where NAME = 449 and ISSENT = 0";
FbCommand mCommand = new FbCommand(SQLCommandText, mConnection, mTransaction);
FbDataReader mReader = mCommand.ExecuteReader();
while (mReader.Read())
{
var values = new object[mReader.FieldCount];
{
mReader.GetValues(values);
var dbResult = values.Distinct().ToArray();
var dbResults = (string.Join("|", dbResult));
var result = new
{
ID = dbResult[0],
NAME = dbResult[1],
DATE = dbResult[2],
};
var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(result);
using FbConnection UpdateConnection = new(connectionString);
UpdateConnection.Open();
FbCommand writeCommand = new("update TABLE set ISSENT = #isSentValue where ID= #idValue", UpdateConnection);
writeCommand.Parameters.Add("#isSentValue", 1);
writeCommand.Parameters.Add("#idValue", dbResult[0]);
writeCommand.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
Log.Fatal(ex, "Problem reading the database.");
}
await Task.Delay(10000, stoppingToken);
}
}
}
Because you are using a worker and running async operation, I would not recommend to mix conditions that will complicate the already cumbersome debugging process.
I would add a column to your table as bit and use it as a flag column called IsSent
and then your query would look like:
select...... where name = X and IsSent = Y ...."
this way you will get only rows that are not sent.
you can otherwise query the row in the code and check if the ID was sent.
cleaner, better, easier.
Make your code maintainable.
I would suggest to implement MemCache or simple memory caching on your worker service, by caching your new data. Either the whole or just the key identifier field value. Then, you can pass that value the next time you query the Db where the Id > CachedId or Id != CachedId order by desc.
At any point, when you retrieve the data, you cache it/upsert your cache with that Id.
These are some examples/references for your knowledge
https://qawithexperts.com/article/c-sharp/in-memory-cache-c-explanation-with-example/302
I am executing a ORACLE Stored procedure using System.OracleClient.OracleCommand and set CommandTimeout = 5; (for example)
But I want to set a timeout such that if the command object execution takes more than say 5 minutes it should get aborted (getting exception...OracleException) so that I can show an error message to the user. Let me know how can this be done. This is my written code example.
try
{
_dbConnectionString.Open();
var cmdOracle = new OracleCommand("hfghgh", _dbConnectionString)
{
CommandType = CommandType.StoredProcedure
};
OracleCommandBuilder.DeriveParameters(cmdOracle);
cmdOracle.Parameters["inputParam"].Value = 1;
tran =_dbConnectionString.BeginTransaction(IsolationLevel.ReadCommitted);
cmdOracle.Transaction = tran;
cmdOracle.CommandTimeout = 5;
await cmdOracle.ExecuteNonQueryAsync();
tran.Commit();
return res = cmdOracle.Parameters["outputParam"].Value.ToString();
}
catch (OracleException ex)
{
dynamic exOra = ex;
int errorNo = exOra.Number;
if (errorNo == 01013)
{
throw new ResponseFailException(ex);
}
else
{
throw ex;
}
}
I have an application currently fully operational using OracleDB.Recently, I converted my OracleDB into PostgreSQL and I am facing a weird problem.Whenever I try to access my procedure of PostGreSQL through application, sometimes it works perfectly and sometimes does not.It gives an error saying that "this procedure(my procedure name) does not exist,while it exists in the database and works perfectly with pgAdmin query tool. I am really confused,please help me out. Here I am giving one of my sample procedure below and attaching error log too.
CREATE OR REPLACE FUNCTION sylvia.pro_occupation_add(
p_occupationid bigint,
p_occupationname text,
p_occupationdetails text)
RETURNS void
LANGUAGE 'plpgsql'
AS $BODY$
begin
insert into sylvia.occupation (occupationid,occupationname,occupationdetails)
values (p_occupationid, p_occupationname, p_occupationdetails);
end;
$BODY$;
C# code :
private DataSet _createOccupation(DataSet inputDS)
{
ErrorDS errDS = new ErrorDS();
EmployeeHistDS employeeHistDS = new EmployeeHistDS();
DBConnectionDS connDS = new DBConnectionDS();
//extract dbconnection
connDS.Merge(inputDS.Tables[connDS.DBConnections.TableName], false, MissingSchemaAction.Error);
connDS.AcceptChanges();
//create command
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.CommandText = "PRO_OCCUPATION_ADD";
cmd.CommandType = CommandType.StoredProcedure;
employeeHistDS.Merge(inputDS.Tables[employeeHistDS.Occupation.TableName], false, MissingSchemaAction.Error);
employeeHistDS.AcceptChanges();
foreach (EmployeeHistDS.OccupationRow row in employeeHistDS.Occupation)
{
long genPK = IDGenerator.GetNextGenericPK();
if (genPK == -1)
{
return UtilDL.GetDBOperationFailed();
}
cmd.Parameters.Add("p_OccupationId", genPK);
cmd.Parameters.Add("p_OccupationName", row.OccupationName);
if (!row.IsOccupationDetailsNull()) cmd.Parameters.Add("p_OccupationDetails", row.OccupationDetails);
else cmd.Parameters.Add("p_OccupationDetails", DBNull.Value);
bool bError = false;
int nRowAffected = -1;
nRowAffected = ADOController.Instance.ExecuteNonQuery(cmd, connDS.DBConnections[0].ConnectionID, ref bError);
if (bError == true)
{
ErrorDS.Error err = errDS.Errors.NewError();
err.ErrorCode = ErrorCode.ERR_DB_OPERATION_FAILED.ToString();
err.ErrorTier = ErrorTier.ERR_TIER_DL.ToString();
err.ErrorLevel = ErrorLevel.ERR_LEVEL_SEVER.ToString();
err.ErrorInfo1 = ActionID.ACTION_OCCUPATION_ADD.ToString();
errDS.Errors.AddError(err);
errDS.AcceptChanges();
return errDS;
}
}
errDS.Clear();
errDS.AcceptChanges();
return errDS;
}
public int ExecuteNonQuery(NpgsqlCommand cmdInsertUpdateDelete, int connectionID, ref bool bError)
{
CConnectionInfo connInfo = (CConnectionInfo)this.m_hashConn[connectionID];
if (connInfo == null)
{
AppLogger.LogWarning("Connection ID '" + connectionID + "' does not exist in connection pool.\nCould not execute ExecuteNonQuery method.");
bError = true;
return -1;
}
NpgsqlConnection conn = connInfo.m_Conn_PG;
NpgsqlTransaction tx = connInfo.m_Tx_PG;
cmdInsertUpdateDelete.Connection = conn;
cmdInsertUpdateDelete.Transaction = tx;
try
{
bError = false;
return cmdInsertUpdateDelete.ExecuteNonQuery();
}
catch (Exception ex)
{
WriteErrorLog(ex, connectionID);
AppLogger.LogFatal("Error executing ExecuteNonQuery method.\n" + cmdInsertUpdateDelete.CommandText, ex);
invalidateConnectionID(connectionID);
bError = true;
return -1;
}
finally
{
cmdInsertUpdateDelete.Transaction = null;
cmdInsertUpdateDelete.Connection = null;
}
}
Error Log
I am writing a CLR function to parse a table column and write the results into another table. Basic requirement is parsing the Detail column, which contains a Time part and an ID part. Results will be the time difference between two Ids.
Ex: Time1,Id1;Time2,Id2;Time3,Id3... and so on
Time2-Time1 is time taken by Id1 in seconds.
Same function is working in normal console application but CLR function is throwing the exception when I call it from SQL server.
Error is
A .NET Framework error occurred during execution of user-defined routine or aggregate "Function1":
System.Security.HostProtectionException: Attempted to perform an operation that was forbidden by the CLR host.
The protected resources (only available with full trust) were: All
The demanded resources were: UI
System.Security.HostProtectionException:
at UserDefinedFunctions.Function1(String msisdn, String promptdetails)
My code is:
SqlConnection conn = new SqlConnection();
SqlCommand cmd = new SqlCommand();
int count = 0;
string PromptPart = string.Empty;
string PrevPromptPart = string.Empty;
DateTime TimePart;
TimePart = new DateTime();
DateTime PrevTimePart;
PrevTimePart = new DateTime();
TimeSpan difference;
try
{
count++;
conn.ConnectionString = "Context Connection=true";
cmd.Connection = conn;
String[] string1 = promptdetails.Split(";".ToCharArray());
foreach (var item1 in string1)
{
count++;
String[] string2 = item1.Split(",".ToCharArray());
PromptPart = string2[1];
TimePart = DateTime.ParseExact(string2[0], "M/d/yyyy h:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture);
if (count > 1)
{
StringBuilder sbQuery = new StringBuilder(1024);
sbQuery.Append("INSERT INTO [Shami].[DBO].[data] (MSISDN,PromptID1,PromptID2,TimeDifference) VALUES");
sbQuery.Append("('");
sbQuery.Append(msisdn);
sbQuery.Append("',");
difference = TimePart.Subtract(PrevTimePart);
sbQuery.Append("'");
sbQuery.Append(PrevPromptPart);
sbQuery.Append("','");
sbQuery.Append(PromptPart);
sbQuery.Append("',");
sbQuery.Append(difference.Seconds);
sbQuery.Append(")");
string sub = string.Empty;
sub = sbQuery.ToString();
try
{
conn.Open();
cmd = new SqlCommand(sub);
SqlContext.Pipe.ExecuteAndSend(cmd);
}
catch (Exception ie)
{
Console.WriteLine("Error..");
}
}
if (count <= 1)
{
StringBuilder sbQuery = new StringBuilder(1024);
sbQuery.Append("INSERT INTO [Shami].[DBO].[data] (MSISDN,PromptID1,PromptID2,TimeDifference) VALUES");
sbQuery.Append("('");
sbQuery.Append(msisdn);
sbQuery.Append("',");
sbQuery.Append("'_'");
sbQuery.Append(",");
sbQuery.Append(PromptPart);
sbQuery.Append(",");
sbQuery.Append("'0'");
sbQuery.Append(")");
string sub = string.Empty;
sub = sbQuery.ToString();
try
{
conn.Open();
cmd = new SqlCommand(sub);
SqlContext.Pipe.ExecuteAndSend(cmd);
}
catch (Exception ie)
{
Console.WriteLine("Error..");
}
}
PrevPromptPart = PromptPart;
PrevTimePart = TimePart;
}
}
catch (Exception)
{ ;}
finally
{
conn.Close();
conn.Dispose();
cmd.Dispose();
}
return msisdn;
Please let me know where I'm going wrong. I can't debug in CLR.
You would just need to replace your line
Console.WriteLine("Error...");
with this line:
SqlContext.Pipe.Send("Error...");
This will do the same thing for you and it will run