Thread abort in Window Service in C# - 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)
{
}

Related

SQLite table doesn't get updated

I have a problem. I created a SwitchButton and want to store the state in a database table. So I created this code to debug:
SettingSwitch.CheckedChange += (s, b) =>
{
SettingDb testsetting = new SettingDb
{
Name = mItems[position].Name,
};
SettingDb test = MainActivity.db.SelectRowFromTableSettings(testsetting);
if (test != null)
{
bool SwitchValueBool = Convert.ToBoolean(test.Value);
}
bool isChecked = ValueDictionary[position];
if(isChecked == true)
{
isChecked = false;
}
else if(isChecked == false)
{
isChecked = true;
}
SettingDb setting = new SettingDb()
{
Name = SettingName.Text,
Type = "Switch",
Value = isChecked.ToString()
};
MainActivity.db.UpdateTableSettings(setting);
ValueDictionary[position] = isChecked;
SettingDb test2 = MainActivity.db.SelectRowFromTableSettings(testsetting);
if (test2 != null)
{
bool SwitchValueBool = Convert.ToBoolean(test2.Value);
}
};
The expected outcome should be:
test.Value = False
test2.Value = Opposite of test.Value, so True
But now the value I get from the table is always False. Here is the update function:
string folder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
public bool UpdateTableSettings(SettingDb setting)
{
try
{
using (var connection = new SQLiteConnection(System.IO.Path.Combine(folder, "Settings.db")))
{
connection.BeginTransaction();
connection.Query<SettingDb>("UPDATE SettingDb SET Value=? WHERE Name=?", setting.Value, setting.Name);
//connection.Update(setting);
connection.Commit();
return true;
}
}
catch (SQLiteException ex)
{
Log.Info("SQLiteEx", ex.Message);
return false;
}
}
public SettingDb SelectRowFromTableSettings(SettingDb setting)
{
try
{
using (var connection = new SQLiteConnection(System.IO.Path.Combine(folder, "Settings.db")))
{
return connection.Query<SettingDb>("SELECT * FROM SettingDb WHERE Name=?", setting.Name).FirstOrDefault();
}
}
catch (SQLiteException ex)
{
Log.Info("SQLiteEx", ex.Message);
return null;
}
}
The table value doesn't get updated!!!
Can someone tell me what I am doing wrong?
Please let me know!
According to your description, you want to update sqlite database table, please take a look the following code and modify the update function.
static void UpdateDatabase(int primaryKey, string newText, int newValue)
{
string path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments), "mydatabase.db");
var db = new SQLiteConnection(path, false);
string sql = "UPDATE MyTable SET MyTextColumn = ?, MyValueColumn = ? WHERE MyPrimaryKey= ?";
string[] parms = new String[] { newText, newValue.ToString(), primaryKey.ToString() };
var cmd = db.CreateCommand(sql, parms);
cmd.ExecuteNonQuery();
}

How to call a method in .cs file which was implemented in code behind?

I have a button click event in code behind file as follows:
protected void btnArchive_Click(object sender, EventArgs e)
{
try
{
if (projectId == 0)
{
return;
}
Int32 serverPathId = 0;
ProjectArchiveResponse archiveResponse;
if (!int.TryParse(this.ddlSourceServer.SelectedValue, out serverPathId))
return;
if (string.IsNullOrEmpty(hidFileCount.Value))
{
this.ShowMsg(this.divMessage, Resources.Resource.ProjectFileArchiveNotAllowed, MessageType.Failed);
//The project files couldn't be archived until archive operation was completed.
return;
}
ProjectManager projectManager = new ProjectManager(null, BasePage.GetCurrentUser(), null) { IsServiceCall = false};
try
{
archiveResponse = projectManager.StartProjectArchive(projectId, false, () =>
{
foreach (Control control in tdFileList.Controls.Cast<Control>())
{
if (control is Dell.AFP.UserControl.ProjectFileListBaseControl)
{
((ProjectFileListBaseControl)control).Refresh();
}
}
}, false);
if (archiveResponse.MassivePackageID > 0)
{
this.ViewState["transferPackageId"] = archiveResponse.MassivePackageID;
PopupMonitor(archiveResponse.MassivePackageID);
}
//handled for any erorrs while submitting massive package or any unhandled exceptions will be taken care here
if (archiveResponse._CustomError != null && !string.IsNullOrEmpty(archiveResponse._CustomError.Erorrmessage))
{
if (!archiveResponse._CustomError._Erorrtype.Equals(MessageType.Info))
logger.ErrorFormat("Error occurred with details : {0}", archiveResponse._CustomError.Erorrmessage);
ShowMsg(divMessage, archiveResponse._CustomError.Erorrmessage, (MessageType)archiveResponse._CustomError._Erorrtype);
}
}
catch (KnownErrorException ke)
{
//logger.Fatal("UnExpected exception occured. Exception Details " + ke.Message);
logger.Fatal(ke.Message);
if (ke.Error.Type.Equals(DELL.AFP.Management.Exceptions.ErrorType.Warning))
this.ShowMsg(this.divMessage, ke.Message, MessageType.Info);
else
this.ShowMsg(this.divMessage, ke.Message, MessageType.Failed);
}
catch (Exception ke)
{
logger.ErrorFormat("UnExpected exception has occured with details : {0} - {1}", ke.Message, ke.StackTrace);
//ShowMsg(divMessage, "UnExpected exception has occured. Details are logged. Please try after sometime", MessageType.Failed);
ShowMsg(divMessage,ke.Message, MessageType.Failed);
}
}
In this event I am calling a method StartProjectArchive which is in ProjectManager.cs file
StartProjectArchive method in ProjectManager.cs is as follows:
public ProjectArchiveResponse StartProjectArchive(int projectID, bool promoteAfterArchive, Action uiRefresh, bool waitTillTransfered, string archiveNotificationUrl = null)
{
ProjectArchiveResponse projectArchiveResponse = new ProjectArchiveResponse() { ProjectID = projectID, MassivePackageID = -1 };
string sourceServerPath = String.Empty;
int packageID =0;
Int32 sourceServerPathID = GetSourceServerPath(projectID, out sourceServerPath);
var filesWhichNeedsToBeArchived = GetFilesWhichNeedsToBeArchived(projectID, sourceServerPathID, uiRefresh);
if (objFilesNotInSourceServer != null && objFilesNotInSourceServer.Count > 0)
KnownErrorException.Throw("ePRJARCMISSFILE01", string.Join(",", objFilesNotInSourceServer.ToArray()));
if (filesWhichNeedsToBeArchived != null)
{
MassiveServiceClientProxy proxy = new MassiveServiceClientProxy();
Dictionary<string, string> files = new Dictionary<string, string>();
filesWhichNeedsToBeArchived.Select(file => new
{
SourcePath = file.FileName,
DestinationPath = Path.Combine(ConfigurationManager.AppSettings["ArchiveProcessPrefixFolder"],
Path.GetDirectoryName(file.FileName), Path.GetFileName(file.FileName),
projectFilelist.Where(pf => string.Compare(pf.FileName, file.FileName, true) == 0).First().VersionID.ToString(),
Path.GetFileName(file.FileName))
}).ToList().
ForEach(file =>
{
if (!files.ContainsKey(file.SourcePath))
files.Add(file.SourcePath, file.DestinationPath);
});
if (files.Count > 0)
{
string packageDescription = "AFP 4.0: " + projectID.ToString(),
targetServerGroupName = archiveServer.MassiveServerGroupName,
userSuppliedId = "AFP 4.0: " + EndUserInfo.UserName;
try
{
packageID = proxy.SubmitPackageWithDestinationPath(files, packageDescription, new[] { sourceServerPath },
targetServerGroupName, userSuppliedId, MassiveService.MassivePriority.URGENT, true);
}
catch (Exception ex)
{
if (IsServiceCall == true)
KnownErrorException.Throw("wPRJARCMASER01");
else
return new ProjectArchiveResponse() { _CustomError = new CustomError { _Erorrtype = Model.ErrorType.Failed, Erorrmessage = ex.Message } };
}
if (packageID > 0)
{
ProjectFileBizManager projectFileBM = new ProjectFileBizManager();
projectFileBM.InsertArchiveTransferPackageByProjectFileList(
GetProjectFileIDsByFileName(projectID, filesWhichNeedsToBeArchived.Select(file => file.FileName).ToArray()), filesWhichNeedsToBeArchived.Select(file => file.FileName).ToArray(), packageID, projectID, EndUserInfo.UserId);
TransferPackageBizManager transferPackageBM = new TransferPackageBizManager();
if (promoteAfterArchive)
{
transferPackageBM.UpdateTransferPackageFeature(packageID, promoteAfterArchive);
}
projectArchiveResponse.MassivePackageID = packageID;
if (waitTillTransfered)
{
Task<ProjectArchiveResponse> mainTask = Task<ProjectArchiveResponse>.Factory.StartNew(
() =>
{
Task<Enums.TransferStatusEnum> packageTransfer = Task<Enums.TransferStatusEnum>.Factory.StartNew(
() =>
{
try
{
TransferPackage transferPackage = null;
while (true)
{
transferPackage = transferPackageBM.GetTransferPackage(packageID);
if (transferPackage.TransferStatus.TransferStatusId == (int)Enums.TransferStatusEnum.Submitted || transferPackage.TransferStatus.TransferStatusId == (int)Enums.TransferStatusEnum.Transferring)
Thread.Sleep(8000);
else
break;
}
logger.DebugFormat("Massive package status : {0} for Package : {1}", (Enums.TransferStatusEnum)transferPackage.TransferStatus.TransferStatusId, transferPackage.TransferPackageId);
return (Enums.TransferStatusEnum)transferPackage.TransferStatus.TransferStatusId;
}
catch (Exception exp)
{
logger.ErrorFormat("Project Archive Error, while trying to find massive package status : {0}", exp);
return Enums.TransferStatusEnum.Submitted;
}
});
try
{
Int32 timeOutInMins = (ConfigurationManager.AppSettings["ProjectArchive_PackageMonitorTimeoutInMinutes"] == null) ? 60 :
Convert.ToInt32(ConfigurationManager.AppSettings["ProjectArchive_PackageMonitorTimeoutInMinutes"]);
if (!Task.WaitAll(new Task[] { packageTransfer }, timeOutInMins * 60 * 1000))
{
projectArchiveResponse.Timedout = true;
projectArchiveResponse.TransferStatus = Enums.TransferStatusEnum.Submitted;
}
else
projectArchiveResponse.TransferStatus = packageTransfer.Result;
logger.DebugFormat("Project Archive Response, Project ID: {0}\n Package ID : {1},\n IsTimedout : {2},\n Timeout value : {3} minutes, \n Transfer Status : {4}", projectArchiveResponse.ProjectID, projectArchiveResponse.MassivePackageID, projectArchiveResponse.Timedout, timeOutInMins, projectArchiveResponse.TransferStatus);
}
catch (Exception exp)
{
logger.ErrorFormat("Project Archive Error, while waiting to fetch massive package status : {0}", exp);
}
return projectArchiveResponse;
});
if (!string.IsNullOrEmpty(archiveNotificationUrl))
{
mainTask.ContinueWith((a) =>
{
try
{
AFPArchiveNotifyProxy archiveNotification = new AFPArchiveNotifyProxy();
ArchiveNotificationService.ProjectArchiveResponse archiveResponse = new ArchiveNotificationService.ProjectArchiveResponse()
{
MassivePackageID = a.Result.MassivePackageID,
ProjectID = a.Result.ProjectID,
IsTimedout = a.Result.Timedout,
ArchiveStatus = (Enum.Parse(typeof(ArchiveNotificationService.ArchiveStatusEnum), (a.Result.TransferStatus.ToString())) as ArchiveNotificationService.ArchiveStatusEnum?).Value
};
MassiveServiceClientProxy massiveServiceClientProxy = new MassiveServiceClientProxy();
FileTransferRequest[] fileTransferRequests = massiveServiceClientProxy.GetFileStatus(a.Result.MassivePackageID);
archiveResponse.Files = fileTransferRequests.Select(f => f.FileName).ToArray();
archiveNotification.ProjectArchiveUpdate(archiveNotificationUrl, archiveResponse);
logger.DebugFormat("Project Archive Response Notification, Project ID: {0}\n Package ID : {1},\n IsTimedout : {2},\n Archive Status :{3},\n Notification Url : {4},\n Total Files : {5}", archiveResponse.ProjectID, archiveResponse.MassivePackageID, archiveResponse.IsTimedout, archiveResponse.ArchiveStatus, archiveNotificationUrl, archiveResponse.Files.Count());
logger.DebugFormat("Package ID : {0}, Files : {1}", archiveResponse.MassivePackageID, string.Join(",", archiveResponse.Files.ToArray()));
}
catch (Exception exp)
{
logger.ErrorFormat("Project Archive Error, while invoking archive notification : {0}", exp);
}
});
projectArchiveResponse.TransferStatus = Enums.TransferStatusEnum.Submitted;
return projectArchiveResponse;
}
else
{
mainTask.Wait();
}
}
}
else
{
if (IsServiceCall == true)
KnownErrorException.Throw("ePRJARCMASS01");
else
return new ProjectArchiveResponse() { _CustomError = new CustomError { _Erorrtype = Model.ErrorType.Failed, Erorrmessage = "Massive has not returned the massive packageid" } };
}
}
else
{
// this.ShowMsg(this.divMessage, Resources.Resource.NoFilesToArchive, MessageType.Info);
if (IsServiceCall == true)
KnownErrorException.Throw("wPRJARCNOFILES01");
else
return new ProjectArchiveResponse() { _CustomError = new CustomError { _Erorrtype = Model.ErrorType.Info, Erorrmessage = "There are no files to archive" } };
}
}
return projectArchiveResponse;
}
In this we are taking a parameter as "Action uiRefresh" . we are calling this uiRefresh as method in GetFilesWhichNeedsToBeArchived which was in startArchiveProject method. This Refresh method in tunrn calls the method in code behind file. This was passed as a control when we are invoking startArchiveProject in code behind file. Now I have one more thing which I need to implement. I have a method Pop-Up files in code behind file. I need to call that in ProjectManager.cs class inside the Method GetFilesWhichNeedsTobeArchive. In that pop-up I will have a button and checkboxes. Upon the selection user I need to get the details from pop-up and then I have to continue with the remaining execution in ProjectManger.cs page.
Can someone help on this?
Assuming that you have a button named btnArchive then the add click event subscription, pointing to the method you have (which looks like click-event handle proc)
btnArchive.Click+=(s,e)=>btnArchive_Click(s,e);
Regards

EventStore duplicate commit exception

UPDATE:
We are getting getting System.Data.SqlClient.SqlException. The message is:
Violation of PRIMARY KEY constraint 'PK_Commits'. Cannot insert duplicate key in object 'dbo.Commits'.\r\nThe statement has been terminated
It seems like EventStore is using streamid and commitid as unique id.
We use event store to append events as below.
public bool TryAppend(object[] content)
{
if (content == null)
throw new ArgumentNullException("content");
try
{
using (var stream = m_storage.OpenStream(m_streamID, 0, int.MaxValue))
{
var versionInStore = stream.StreamRevision;
content.ToList().ForEach(m =>
{
var version = ++versionInStore;
var key = string.Format("{0}-{1:00000000}", m.GetType().Name, version);
var savedMessage = new SavedRecord(key, version, m);
stream.Add(new EventMessage { Body = savedMessage });
});
stream.CommitChanges(Guid.NewGuid());
}
return true;
}
catch (Exception e)
{
m_logger.LogError(e);
return false;
}
}
The configuration of EventStore is as below. We are using Sql Serer 2008 as persistance store.
return Wireup.Init()
.LogToOutputWindow()
.UsingSqlPersistence(m_connectionName)
.WithDialect(new MsSqlDialect())
.EnlistInAmbientTransaction() // two-phase commit
.InitializeStorageEngine()
.UsingJsonSerialization()
.Compress()
.UsingSynchronousDispatchScheduler()
.DispatchTo(new DelegateMessageDispatcher(DispatchCommit))
.Build();
Any ideas why are gettin the dupplicate commit exception?
Thanks
Have got the same issue; in my case it was probably because of different threads was adding different events to the stream with same id at the same time.
Have writtent the following code to be able to retry adding events:
private void TryAddEvent(IStoreEvents storeEvents, IUserEvent anEvent, Guid streamId)
{
var isCommitSuccessful = false;
for (var i = 0; i < 10 && !isCommitSuccessful; i++)
{
try
{
using (var stream = storeEvents.OpenStream(streamId, 0, int.MaxValue))
{
stream.Add(new EventMessage {Body = anEvent});
if (stream.UncommittedEvents.All(e => e.Body != anEvent))
{
stream.Add(new EventMessage {Body = anEvent});
}
stream.CommitChanges(Guid.NewGuid());
}
isCommitSuccessful = true;
}
catch (Exception ex)
{
if (!(ex is SqlException) && !(ex is ConcurrencyException))
{
throw;
}
using (var stream = storeEvents.OpenStream(streamId, 0, int.MaxValue))
{
if (stream.CommittedEvents.Any(e => e.Body == anEvent))
{
isCommitSuccessful = true;
}
}
}
}
if (!isCommitSuccessful)
{
throw new ConcurrencyException(String.Format("Cannot add {0} to event store", anEvent.GetType()));
}
}
Hope it would help.

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.

LINQ to SQL submitchanges not doing anything

My issue is the following: i'm trying to build a function to which i could pass a list of items, which would then go to the db with each of those items and update them. I believe the issue is within the way datacontexts are being used but i cannot figure out this issue.
Here is my function that builds the list of items that were changed:
protected void btnSave_Click(object sender, EventArgs e)
{
List<AFF_CMS_FMA> fmasToSave = new List<AFF_CMS_FMA>();
AFF_CMS_FMA newFmaItem = new AFF_CMS_FMA();
foreach (AFF_CMS_FMA fmaItem in FmaLib.fetchAllActiveAssetsInFMA())
{
if (fmaItem.SortOrder != Convert.ToInt32(Request.Form["fmaItem_" + fmaItem.ID + "_SortOrder"]))
{
newFmaItem = fmaItem;
newFmaItem.Name = SecurityLib.SqlSafeString(Request.Form["fmaItem_" + fmaItem.ID + "_Name"]);
newFmaItem.AssetID = Convert.ToInt32(Request.Form["fmaItem_" + fmaItem.ID + "_AssetID"]);
newFmaItem.SortOrder = Convert.ToInt32(Request.Form["fmaItem_" + fmaItem.ID + "_SortOrder"]);
newFmaItem.ImagePathEn = SecurityLib.SqlSafeString(Request.Form["fmaItem_" + fmaItem.ID + "_ImagePathEn"]);
newFmaItem.ImagePathCh = SecurityLib.SqlSafeString(Request.Form["fmaItem_" + fmaItem.ID + "_ImagePathCh"]);
newFmaItem.StartDate = DateTime.Parse(SecurityLib.SqlSafeString(Request.Form["fmaItem_" + fmaItem.ID + "_StartDate"]));
newFmaItem.EndDate = DateTime.Parse(SecurityLib.SqlSafeString(Request.Form["fmaItem_" + fmaItem.ID + "_EndDate"]));
newFmaItem.ClickToUrl = SecurityLib.SqlSafeString(Request.Form["fmaItem_" + fmaItem.ID + "_ClickToUrl"]);
fmasToSave.Add(newFmaItem);
}
}
FmaLib.saveEditedFmas(fmasToSave);
}
here is the function that the foreach loops calls to get all the items that are in the db:
public static List<AFF_CMS_FMA> fetchAllActiveAssetsInFMA()
{
List<AFF_CMS_FMA> results = null;
using (fmaDataContext db = new fmaDataContext())
{
using (TransactionScope ts = new TransactionScope())
{
try
{
if (HttpContext.Current.Cache["fmaActiveList"] == null)
{
db.LoadOptions = loadAll;
results = clsCompiledQuery.getAllActiveFmas(db).ToList();
HttpContext.Current.Cache["fmaActiveList"] = results;
}
else
results = (List<AFF_CMS_FMA>)HttpContext.Current.Cache["fmaActiveList"];
ts.Complete();
}
catch (Exception ex)
{ Transaction.Current.Rollback(); }
}
return results;
}
}
here are the queries being used:
protected static class clsCompiledQuery
{
public static Func<DataContext, IOrderedQueryable<AFF_CMS_FMA>>
getAllActiveFmas = CompiledQuery.Compile((DataContext db)
=> from fma in db.GetTable<AFF_CMS_FMA>()
where fma.IsArchived == false
orderby fma.SortOrder ascending
select fma);
public static Func<DataContext, int,IQueryable<AFF_CMS_FMA>>
getFmaById = CompiledQuery.Compile((DataContext db, int ID)
=> from fma in db.GetTable<AFF_CMS_FMA>()
where fma.ID == ID
select fma);
}
and finally this were im trying to get the save to happen to the db but no exeptions are throwns, yet the db does not change
public static bool saveEditedFmas(List<AFF_CMS_FMA> fmaToSaveList)
{
using (fmaDataContext db = new fmaDataContext())
{
using (TransactionScope ts = new TransactionScope())
{
try
{
foreach (AFF_CMS_FMA fmaItemToSave in fmaToSaveList)
{
AFF_CMS_FMA fmaItemToUpdate = clsCompiledQuery.getFmaById(db, fmaItemToSave.ID).ToList()[0];
fmaItemToUpdate = fmaItemToSave;
db.SubmitChanges();
}
return true;
}
catch (Exception ex)
{
Transaction.Current.Rollback();
return false;
}
}
}
}
I have checked and the table does contain a primary key in the designer. If i do the save from the btnSave_click function by passing a datacontext to the fetchAllActiveAssetsInFMA() then doing submitchanges on that context it works .. but im trying to abstract that from there.
thanks all in advance
Your not calling ts.Complete in function saveEditedFmas.
Also I would recommend calling db.SubmitChanges(); outside of the for loop. And why do you have a transaction in function fetchAllActiveAssetsInFMA? It's only fetching data right? And I'm not quite sure whats happening inside the for loop in save function, looks strange.
I think you should map the properties from fmaItemToSave to fmaItemToUpdate
foreach (var fmaItemToSave in fmaToSaveList)
{
var fmaItemToUpdate = clsCompiledQuery.getFmaById(db, fmaItemToSave.ID).First();
fmaItemToUpdate.Name = fmaItemToSave.Name;
fmaItemToUpdate.AssetID = fmaItemToSave.AssetID;
//And the rest of the properties
}
db.SubmitChanges();

Categories