inside a custom Epicor Function, lock reading of table until transaction is done
basically this is a simple function: Look at table UD05, grab the record with column Key1 == “ErpID”
then increment that record’s column value in Character01
save the new value to the db and return the original value.
the problem is multiple calls happening simultaneously (multi threading from client side), both calls are able to read the value before the first updates it. thus resulting in both calls returning the same value instead of waiting their turn.
This is a shorthand of the code
using(var txScope = IceContext.CreateDefaultTransactionScope())
{
//TODO: Determine the proper locking mode (i.e. UpdLock, HoldLock, etc.)
//Retrieve the ERP ID row from the UD05 table and temporarily lock the record
var r = this.Db.UD05.With(LockHint.HoldLock)// where Key1 == UD05_KEY1_VALUE //.FirstOrDefault(x => x.Key1 == UD05_KEY1_VALUE);
var char01 = Convert.ToInt32(r.Character01);
this.outputval = char01;
char01 = char01 + 1;
r.Character01 = char01.ToString();
this.Db.SaveChanges();
txScope.Complete();
}
I wish to essentially use tablockx but that is not a LockHint option
Yeah don’t use a 3rd party library just use the built DLL in sequence as you show. That Sequence DLL does show up in select assembly you just have to wait a bit
wow, I had to wait around 2min for that first dll to show up, thanks
when I make a call to this new function (internal to the library) or even when I just used the code above without making it it’s own function I get this error:
The underlying provider failed on EnlistTransaction.
…
Implicit distributed transactions have not been enabled. If you’re intentionally starting a distributed transaction, set TransactionManager.ImplicitDistributedTransactions to true.
I tried flipping the Requires transaction on and off and it does not seem to stop this error. This function is a couple layers deep and tried different combinations of the functions and their reqTran bit but to no avail.
current function structure
//GetNewAndExistingErpIDsByBomItem
//(this gets called by the client by:
var resp = await EpicorRest.EfxPostAsync(libraryName, "GetNewAndExistingErpIDsByBomItem" ,jsonData);
//that can call GetNextSequence
I couldn’t seem to call the initial function GetNewAndExistingErpIDsByBomItem from the client if I turn ReqTran on for that one.
(edited to reflect simpler function call setup)
I think there is a ton of context missing around your requirements. Saying this is a few layers deep makes me raise an eyebrow.
The error you are getting is because you are trying to do a transaction inside another transaction in a remote setting and that generally won’t work
I suspect some of the “layers” have require transaction or are creating a transaction context themselves. You are going to have to peel back this onion for us if you want us to try and help further, we need more explicit context.
ok, I have figured out my issue, thank you guys for all your help!
In the parent function, I was already in a transaction and it seems like the GetNextSequence call is not something that can be in a transaction as it can’t be rolled back.
I was able to move this logic out of the transaction and successfully call it!
I just have one follow up question, is there a way to see what the current value is without incrementing it? just for visibility outside the functions? like a table I can query from SSMS