SQLite connection strategies - c#

I have a database that may be on the network drive.
There are two things that I want to achieve:
When the first user connects to it in read-only mode (he doesn't
have a read-write access to the location, or the database is
read-only), other users must use the read-only connection also (even
if they have RW access).
When the first user connects to it in RW mode, others can not
connect to the database at all.
I'm using SQLite, and the concurrency should not be the problem, as the database should never be used by more than 10 people at the same time.
UPDATE: This is a sample that I'm trying to make work, so I could implement it in the program itself. Almost everything can be changed.
UPDATE: Now when I finally understood what #CL. was telling me, I made it work and this is the updated code.
using System.Diagnostics;
using System.Linq;
using System.IO;
using DbSample.Domain;
using DbSample.Infrastructure;
using NHibernate.Linq;
using NHibernate.Util;
namespace DbSample.Console
{
class Program
{
static void Main(string[] args)
{
IDatabaseContext databaseContext = null;
databaseContext = new SqliteDatabaseContext(args[1]);
var connection = LockDB(args[1]);
if (connection == null) return;
var sessionFactory = databaseContext.CreateSessionFactory();
if (sessionFactory != null)
{
int insertCount = 0;
while (true)
{
try
{
using (var session = sessionFactory.OpenSession(connection))
{
string result;
session.FlushMode = NHibernate.FlushMode.Never;
var command = session.Connection.CreateCommand();
command.CommandText = "PRAGMA locking_mode=EXCLUSIVE";
command.ExecuteNonQuery();
using (var transaction = session.BeginTransaction(ReadCommited))
{
bool update = false;
bool delete = false;
bool read = false;
bool readall = false;
int op = 0;
System.Console.Write("\nMenu of the day:\n1: update\n2: delete\n3: read\n4: read all\n0: EXIT\n\nYour choice: ");
op = System.Convert.ToInt32(System.Console.ReadLine());
if (op == 1)
update = true;
else if (op == 2)
delete = true;
else if (op == 3)
read = true;
else if (op == 4)
readall = true;
else if (op == 0)
break;
else System.Console.WriteLine("Are you retarded? Can't you read?");
if (delete)
{
System.Console.Write("Enter the ID of the object to delete: ");
var objectToRemove = session.Get<MyObject>(System.Convert.ToInt32(System.Console.ReadLine()));
if (!(objectToRemove == null))
{
session.Delete(objectToRemove);
System.Console.WriteLine("Deleted {0}, ID: {1}", objectToRemove.MyName, objectToRemove.Id);
deleteCount++;
}
else
System.Console.WriteLine("\nObject not present in the database!\n");
}
else if (update)
{
System.Console.Write("How many objects to add/update? ");
int number = System.Convert.ToInt32(System.Console.ReadLine());
number += insertCount;
for (; insertCount < number; insertCount++)
{
var myObject = session.Get<MyObject>(insertCount + 1);
if (myObject == null)
{
myObject = new MyObject
{
MtName = "Object" + insertCount,
IdLegacy = 0,
};
session.Save(myObject);
System.Console.WriteLine("Added {0}, ID: {1}", myObject.MyName, myObject.Id);
}
else
{
session.Update(myObject);
System.Console.WriteLine("Updated {0}, ID: {1}", myObject.MyName, myObject.Id);
}
}
}
else if (read)
{
System.Console.Write("Enter the ID of the object to read: ");
var objectToRead = session.Get<MyObject>(System.Convert.ToInt32(System.Console.ReadLine()));
if (!(objectToRead == null))
System.Console.WriteLine("Got {0}, ID: {1}", objectToRead.MyName, objectToRead.Id);
else
System.Console.WriteLine("\nObject not present in the database!\n");
}
else if (readall)
{
System.Console.Write("How many objects to read? ");
int number = System.Convert.ToInt32(System.Console.ReadLine());
for (int i = 0; i < number; i++)
{
var objectToRead = session.Get<MyObject>(i + 1);
if (!(objectToRead == null))
System.Console.WriteLine("Got {0}, ID: {1}", objectToRead.MyName, objectToRead.Id);
else
System.Console.WriteLine("\nObject not present in the database! ID: {0}\n", i + 1);
}
}
update = false;
delete = false;
read = false;
readall = false;
transaction.Commit();
}
}
}
catch (System.Exception e)
{
throw e;
}
}
sessionFactory.Close();
}
}
private static SQLiteConnection LockDbNew(string database)
{
var fi = new FileInfo(database);
if (!fi.Exists)
return null;
var builder = new SQLiteConnectionStringBuilder { DefaultTimeout = 1, DataSource = fi.FullName, Version = 3 };
var connectionStr = builder.ToString();
var connection = new SQLiteConnection(connectionStr) { DefaultTimeout = 1 };
var cmd = new SQLiteCommand(connection);
connection.Open();
// try to get an exclusive lock on the database
try
{
cmd.CommandText = "PRAGMA locking_mode = EXCLUSIVE; BEGIN EXCLUSIVE; COMMIT;";
cmd.ExecuteNonQuery();
}
// if we can't get the exclusive lock, it could mean 3 things
// 1: someone else has locked the database
// 2: we don't have a write acces to the database location
// 3: database itself is a read-only file
// So, we try to connect as read-only
catch (Exception)
{
// we try to set the SHARED lock
try
{
// first we clear the locks
cmd.CommandText = "PRAGMA locking_mode = NORMAL";
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT COUNT(*) FROM MyObject";
cmd.ExecuteNonQuery();
// then set the SHARED lock on the database
cmd.CommandText = "PRAGMA locking_mode = EXCLUSIVE";
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT COUNT(*) FROM MyObject";
cmd.ExecuteNonQuery();
readOnly = true;
}
catch (Exception)
{
// if we can't set EXCLUSIVE nor SHARED lock, someone else has opened the DB in read-write mode and we can't connect at all
connection.Close();
return null;
}
}
return connection;
}
}
}

Set PRAGMA locking_mode=EXCLUSIVE to prevent SQLite from releasing its locks after a transaction ends.

I don't know if it can be done within db but in application;
You can set a global variable (not sure if it's a web or desktop app) to check if anyone connected and he has a write access or not.
After that you can check the other client's state.

Related

SMO Restore Events Never Fire

We have this scripted restore process , i am trying to add some logging for the percent completed so we have an idea of how far some of our long running backups are into the process
I added an event handler to the PercentCompleted event in our Restore handler but it seems that it never fires as we do not receive any output at all from the callback
Anyone have an idea why this is not working
public void Restore(string backupPath)
{
Logger.Log("Restoring database {0} from backup {1}", Name, backupPath);
using (var con = new SqlConnection(Server.GetConnectionString()))
{
var smoConn = new ServerConnection(con);
smoConn.StatementTimeout = 1200; // FMNET-20792. 20 minutes (default was 10 minutes)
var server = new Server(smoConn);
Logger.Log("Killing all processes in {0}", Name);
try
{
server.KillAllProcesses(Name);
}
catch (FailedOperationException e)
{
Logger.Log("Killing all processed failed with error below. Will still attemp to restore the DB");
Logger.Log(e.ToString());
}
var restore = new Restore();
restore.PercentComplete += (sender, args) =>
{
Logger.Log("Percent Complete {0,3}%", args.Percent);
};
restore.Devices.AddDevice(backupPath, DeviceType.File);
restore.Action = RestoreActionType.Database;
restore.Database = Name;
restore.ReplaceDatabase = true;
string serverDataPath = string.IsNullOrEmpty(server.DefaultFile)
? server.Information.MasterDBPath
: server.DefaultFile;
serverDataPath = Path.GetFullPath(serverDataPath);
Logger.Verbose("Server default data path: {0}", serverDataPath);
string serverLogPath = string.IsNullOrEmpty(server.DefaultLog)
? server.Information.MasterDBLogPath
: server.DefaultLog;
serverLogPath = Path.GetFullPath(serverLogPath);
Logger.Verbose("Server default log path: {0}", serverLogPath);
var files = restore.ReadFileList(server);
int dataFileIndex = 0;
int logFileIndex = 0;
foreach (DataRow row in files.Rows)
{
string logicalName = row["LogicalName"].ToString();
string type = row["Type"].ToString();
string newPhysicalPath;
if (type == "D")
{
newPhysicalPath = string.Format("{0}_Data{1}.mdf", Name,
dataFileIndex > 0 ? dataFileIndex.ToString() : string.Empty);
newPhysicalPath = Path.Combine(serverDataPath, newPhysicalPath);
dataFileIndex++;
}
else if (type == "L")
{
newPhysicalPath = string.Format("{0}_Log{1}.ldf", Name,
logFileIndex > 0 ? dataFileIndex.ToString() : string.Empty);
newPhysicalPath = Path.Combine(serverLogPath, newPhysicalPath);
logFileIndex++;
}
else
{
throw new ApplicationException("Unsupported file type: " + type);
}
var relocateFile = new RelocateFile(logicalName, newPhysicalPath);
Logger.Log("Will relocate {0} to {1}", logicalName, newPhysicalPath);
restore.RelocateFiles.Add(relocateFile);
}
restore.SqlRestore(server);
Logger.Log("Restore complete. Renaming logical files");
var db = server.Databases[Name];
foreach (FileGroup fg in db.FileGroups)
{
for (int i = 0; i < fg.Files.Count; i++)
{
string oldName = fg.Files[i].Name;
string newName = string.Format("{0}_Data{1}", Name, i > 0 ? i.ToString() : string.Empty);
if (!oldName.Equals(newName, StringComparison.InvariantCultureIgnoreCase))
{
Logger.Log("Renaming {0} to {1}", oldName, newName);
fg.Files[i].Rename(newName);
}
else
{
Logger.Log("Oldname equals newname ({0}), nothing to do", oldName);
}
}
}
for (int i = 0; i < db.LogFiles.Count; i++)
{
string oldName = db.LogFiles[i].Name;
string newName = string.Format("{0}_Log{1}", Name, i > 0 ? i.ToString() : string.Empty);
if (!oldName.Equals(newName, StringComparison.InvariantCultureIgnoreCase))
{
Logger.Log("Renaming {0} to {1}", oldName, newName);
db.LogFiles[i].Rename(newName);
}
else
{
Logger.Log("Oldname equals newname ({0}), nothing to do", oldName);
}
}
// Ensure FMAccess user exists in DB and is properly mapped
var fmAccessUser = Env.GetUser("FMAccess");
if (fmAccessUser == null)
{
throw new ApplicationException("Credentials with id=\"FMAccess\" don't exist in the specified environment file. FMAccess user is required when restoring a database.");
}
Logger.Log("Ensuring user {0} exists in the database {1}.", fmAccessUser.Login, Name);
// If a user already exists in DB we drop and re-create it because after restore the mapping to an existing SQL login will be lost anyway.
if (db.Users.Contains(fmAccessUser.Login))
{
Logger.Verbose("User already exists in DB, dropping.");
db.Users[fmAccessUser.Login].Drop();
}
Logger.Verbose("Creating user {0}", fmAccessUser.Login);
var u = new User(db, fmAccessUser.Login) { DefaultSchema = "dbo", Login = fmAccessUser.Login };
u.Create();
var dboRole = db.Roles["db_owner"];
dboRole.AddMember(fmAccessUser.Login);
Logger.Verbose("User created successfully");
}
}

My application in ASP.NET sometimes identifies procedures of postgresql and sometimes shows error "this procedure does not exist"

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

Thread abort in Window Service in C#

I have a window Service which converts the PDF file to html and it is running in 5 threads.
Each thread picks the record from database where status is 0.Once it picks the record from database we are making the status to 64 and making an entry in log file so that other thread should not pick the same record,after successful conversion we are making the status to 256 if any exception we are making the stratus to 128.
Some records are updated to 64 with out any entry in log and they are not even processed further.
Below is the Stored Procedure to pick the single record from database.
Create PROCEDURE [SGZ].[p_GetNextRequestForProcessing]
#InstanceId int
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
set nocount on
Declare #RequestID bigint = null;
SET #RequestID= (
Select
TOP(1) RequestID
From
sgz.PDFTransformationQueue
Where
RequestStatusID=0
);
If (#RequestID is not null)
BEGIN
Begin Transaction;
Update
sgz.PDFTransformationQueue
SET
RequestStatusid=64,
ProcessedInstanceID =#InstanceId,
ProcessStartTime = getutcdate(),
ModifiedDate=getutcdate()
Where
RequestID=#RequestID and
RequestStatusid =0 and
ProcessedInstanceID is null;
if ##rowcount = 0
set #RequestID=null;
Commit Transaction;
END
Select
RQ.VersionNumber,RQ.RequestID, RP.Payload
From
SGZ.RequestPayload RP WITH (NOLOCK),
SGZ.PDFTransformationQueue RQ WITH (NOLOCK)
Where
RP.RequestId=RQ.RequestID AND
ProcessedInstanceID=#InstanceId AND
RequestStatusid =64 AND
RQ.RequestId = #RequestID;
END
And below is the window service code:-
protected override void OnStart(string[] args)
{
PDFTransAutoProcessManager pdfTransAutoProcessManager = new
PDFTransAutoProcessManager();
pdfTransAutoProcessManager.OnProcessStart();
}
And PDFTransAutoProcessManager class:-
private int _runningAsyncThread = 0;
private int _totalAsynThread = 5;
public void OnProcessStart()
{
_logMgr.Info("Process started # " + DateTime.Now);
mainThread = new Thread(new ThreadStart(StartAutoProcess));
mainThread.Priority = ThreadPriority.Highest;
mainThread.Start();
}
private void StartAutoProcess()
{
try
{
while (true)
{
if (_runningAsyncThread < _totalAsynThread)
{
Thread childThread = new Thread(() => ProcessAsync());
Interlocked.Increment(ref _runningAsyncThread);
childThread.Start();
}
Thread.Sleep(100);
}
}
catch (Exception ex)
{ }
}
private void ProcessAsync()
{
try
{
PDFGenieManager pdfGenieManager = new
PDFGenieManager(_logMgr,gmi);
pdfGenieManager.ProcessRawData();
}
catch (Exception ex)
{
_logMgr.Info(ex.Message);
_logMgr.Info(ex.StackTrace);
}
finally
{
Interlocked.Decrement(ref _runningAsyncThread);
}
}
And in PDFGenieManager Class actual database call and conversion will happen.
When it is trying to get records from database some records are updated to 64 with out any entry in log.
Is it related to threading pattern or any problem with stored procedure.
Kindly help thanks in advance.
Below is the PDFGenieManager class code:-
namespace PDFConvertion
{
public class PDFGenieManager
{
public Logger _logMgr;
public GmiManager _gmi;
string _environment;
static readonly object _object = new object();
Dictionary<string, string> _ResourceMetadata = new Dictionary<string, string>();
public PDFGenieManager(Logger logMgr, GmiManager gmi)
{
_logMgr = logMgr;
_gmi = gmi;
_environment = ConfigurationManager.AppSettings["Envoirnment"];
}
public void ProcessRawData()
{
try
{
string unlockKey = string.Empty;
string languageRepair = string.Empty;
bool IsUnicodeRepair = false;
double confidenceScore = 1.0;
var Vendor = string.Empty;
string hiddenText = string.Empty;
DataTable rawData = new DataTable();
RuntimeCacheMgr _runtimeCacheMgr = new RuntimeCacheMgr();
DAL dal = new DAL();
try
{
rawData = dal.GetRawData();
if (rawData != null && rawData.Rows.Count > 0)
{
_logMgr.Info("Picked the record from datbase" + rawData.Rows[0]["Payload"].ToString());
}
if (!_runtimeCacheMgr.Exists(_environment))
{
_ResourceMetadata = dal.getResourcemetaDataValue(_environment);
_runtimeCacheMgr.Add(_environment, _ResourceMetadata);
}
else
{
_ResourceMetadata = _runtimeCacheMgr.Get<Dictionary<string, string>>(_environment);
}
}
catch (SqlException exe)
{
_logMgr.Error("Sql Database Error While Picking the records from database" + exe.Message + exe.StackTrace, exe.InnerException);
}
catch (Exception ex)
{
if (ex != null && !ex.ToString().ToLower().Contains("already exist"))
{
if (rawData != null && rawData.Rows.Count > 0)
{
_logMgr.Error("Exception block Picked the record from datbase" + rawData.Rows[0]["Payload"].ToString());
}
_logMgr.Error("Exception block" + ex.Message);
return;
}
else
{
if (rawData != null && rawData.Rows.Count > 0)
{
_logMgr.Error("Cache block Picked the record from datbase" + rawData.Rows[0]["Payload"].ToString());
}
_logMgr.Error("Cache block" + ex.Message + "" + ex.StackTrace);
}
}
finally
{
if (rawData != null && rawData.Rows.Count > 0)
{
_logMgr.Info("Finally block Picked the record from datbase" + rawData.Rows[0]["Payload"].ToString());
}
}
List<PDFGenieTran> ids = new List<PDFGenieTran>(rawData.Rows.Count);
rawData.AsEnumerable().ToList().ForEach(row => ids.Add(new PDFGenieTran() { Payload = row["Payload"].ToString(), RequestID = Convert.ToInt64(row["RequestID"]), VersionNumber = row["VersionNumber"].ToString() }));
PDFNetStatus PDFstatus = new PDFNetStatus();
foreach (PDFGenieTran pdf in ids)
{
}

Operation is not valid due to the current state of the object. in C#

I had created this method to check number of this record in the table
but it gives me this error message when the value of count(*) is 0
i use this library to connect oracle db
using Oracle.DataAccess.Client;
private int checkPort(int portID)
{
int intCount = 0;
try
{
OracleCommand oraCommand = new OracleCommand();
oraCommand.Connection = new DBManager().getConnection();
oraCommand.CommandText = "select count(*) as num from wireless_port_oid where port_id=:port_id";
oraCommand.Parameters.Add(":port_id", portID);
OracleDataReader Reader= oraCommand.ExecuteReader();
return intCount;
while (**Reader.Read()**)//it gives exception here
//The err Operation is not valid due to the current state of the object.
{
intCount =Convert.ToInt32(Reader[0]);
Reader.Close();
oraCommand.Connection.Close();
oraCommand = null;
if (intCount > 0)
{
return 1;
}
}
Reader.Close();
Reader.Dispose();
oraCommand.Connection.Close();
oraCommand.Connection.Dispose();
oraCommand.Dispose();
return 0;
}
catch (OracleException exception)
{
Console.WriteLine(exception.Message);
return 0;
}
}
You're closing the reader on Count = 0 and then trying to read it again in the while loop.
while (Reader.Read())//it gives exception here
//The err Operation is not valid due to the current state of the object.
{
intCount =Convert.ToInt32(Reader[0]);
Reader.Close();
oraCommand.Connection.Close();
oraCommand = null;
if (intCount > 0)
{
return 1;
}
// if intCOunt == 0 then what? loop again
}
But your code is not valid - I just noticed that you have a return intCount; just before the line you says has an error. I assume that that's just example typo.
I would refactor your code to take adavantage of C#'s using statement:
private int checkPort(int portID) {
string sql = "select count(*) as num from wireless_port_oid where port_id=:port_id";
int intCount = 0;
try {
using(OracleCommand oraCommand = new OracleCommand()) {
using(oraCommand.Connection = new DBManager().getConnection()) {
oraCommand.CommandText = sql;
oraCommand.Parameters.Add(":port_id", portID);
intCount = oraCommand.ExecuteScalar();
}
}
}
catch (OracleException exception) {
Console.WriteLine(exception.Message);
// may be you shouldn't return 0 here possibly throw;
}
return intCount;
}

This IfxTransaction has completed; it is no longer usable

Q:
When I use the transactions ,I'll get the following error on about 1 out of every 100 record.
This IfxTransaction has completed; it
is no longer usable
I can't expect when the error happen or what is the reason of this error.
I try to insert about 607 record in the same transaction.
My code:
public static int InsertGroups(List<Group> groups)
{
DBConnectionForInformix con = new DBConnectionForInformix("");
con.Open_Connection();
con.Begin_Transaction();
int affectedRow = -1;
Dictionary<string, string> groupsParameter = new Dictionary<string, string>();
try
{
foreach (Group a in groups)
{
groupsParameter.Add("id", a.GroupId.ToString());
groupsParameter.Add("name", a.Name);
groupsParameter.Add("studentcount", a.StudentCount.ToString());
groupsParameter.Add("divisiontag", a.DivisionTag.ToString());
groupsParameter.Add("entireclass", a.EntireClass.ToString());
groupsParameter.Add("classid", a.ClassId.ToString());
groupsParameter.Add("depcode", a.DepCode.ToString());
groupsParameter.Add("studycode", a.StudyCode.ToString());
groupsParameter.Add("batchnum", a.BatchNum.ToString());
affectedRow = DBUtilities.InsertEntityWithTrans("groups", groupsParameter, con);
groupsParameter.Clear();
if (affectedRow < 0)
{
break;
}
}
if (affectedRow > 0)
{
con.current_trans.Commit();
}
}
catch (Exception ee)
{
string message = ee.Message;
}
con.Close_Connection();
return affectedRow;
}
public void Begin_Transaction()
{
if (this.connection.State == ConnectionState.Open)
{
this.current_trans = this.connection.BeginTransaction(IsolationLevel.Serializable);
}
}
public static int InsertEntityWithTrans(string tblName, Dictionary<string, string> dtParams, DBConnectionForInformix current_conn)
{
int Result = -1;
string[] field_names = new string[dtParams.Count];
dtParams.Keys.CopyTo(field_names, 0);
string[] field_values = new string[dtParams.Count];
string[] field_valuesParam = new string[dtParams.Count];
dtParams.Values.CopyTo(field_values, 0);
for (int i = 0; i < field_names.Length; i++)
{
field_valuesParam[i] = "?";
}
//----------------------------------------------------------------------------------------------------------------------------------------------
string insertCmd = #"INSERT INTO " + tblName + " (" + string.Join(",", field_names) + ") values (" + string.Join(",", field_valuesParam) + ")";
//----------------------------------------------------------------------------------------------------------------------------------------------
IfxCommand com = new IfxCommand(insertCmd);
for (int j = 0; j < field_names.Length; j++)
{
com.Parameters.Add("?", field_values[j]);
}
try
{
Result = current_conn.Execute_NonQueryWithTransaction(com);
if (current_conn.connectionState == ConnectionState.Open && Result > 0)//OK: logging
{
# region // Log Area
#endregion
}
}
catch (Exception ex)
{
throw;
}
return Result;
}
public int Execute_NonQueryWithTransaction(IfxCommand com)
{
string return_msg = "";
int return_val = -1;
Open_Connection();
com.Connection = this.connection;
com.Transaction = current_trans;
try
{
return_val = com.ExecuteNonQuery();
}
catch (IfxException ifxEx)// Handle IBM.data.informix : mostly catched
{
return_val = ifxEx.Errors[0].NativeError;
return_msg = return_val.ToString();
}
catch (Exception ex)// Handle all other exceptions.
{
return_msg = ex.Message;
}
finally
{
if (!string.IsNullOrEmpty(return_msg))//catch error
{
//rollback
current_trans.Rollback();
Close_Connection();
connectionstate = ConnectionState.Closed;
}
}
return return_val;
}
You seem to be handling errors and rolling back the transaction in two places (in Execute_NonQueryWithTransaction and in InsertGroups.
And the return from Execute_NonQueryWithTransaction is used both to return error codes and to return rows affected. But in InsertGroups it is checked purely as a rows affected.
Could you have an error code from Execute_NonQueryWithTransaction (so transaction rolled back) being treated as success (rows inserted) in InsertGroups and the commit then fails?
Overall the code needs significant cleanup:
A catch block to only throw is pointless and just adds noise.
Just use exceptions for error handling, all normal returns should indicate success.

Categories