- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
UOW and Oracle
Joined: 26-Mar-2010
LLBLGEN 3.1 Rel 31st March .NET Framework 2.0 Winform Application Oracle 9i/10g (MSORACLE)
Dear Support,
I suspect there is some issue with UOW when used with Oracle. Same problem i had posted some time back but that was because of different reason.
What happens is
I have 2 master and detail tables.
First 1 insert into first master and detail tables. Then I update second master table. Then I either insert / update second detail based on business logic.
Now the 1st detail and 2nd detail table have FK field with some master table. If FK is violated in 2nd detail, it still commits 1st master and detail !
Now why I suspect a bug is,
While inserting second detail table, I manually passed FK with larger than the column can hold. In this case it perfectly rolls back all tables in UOW stating precsion is too large. Howmuch every times i save the data, it rolls back all tables so it means nothing wrong in my code
But when FK is violated on second detail table only second master and detail rolls back but 1st master and detail commits . Again Interesting part is on first save it rolls back all tables but on second and subsequent saves, it rolls back only second set. Now if you exit and open again, the same action repeats
It seems you are not using an explicit (extrenal) Transaction object to govern this.
When you call Commit() on a UoW it commits all actions. Then when you add another actions and call Commit() again, it commits all the newly added actions.
Everytime it uses a separate implicit (internal) Transaction, so each Commit() will have nothing to do with the other. unless.
Unless you use a Transaction object, and pass false to the UoW.Commit() overload which accepts an AutoCommit parameter, in order not to call commit of the external transaction object.
And then after calling UoW.Commit() several times, you call Commit() on the Transaction object to Commit the external transaction.
Joined: 26-Mar-2010
Walaa wrote:
It seems you are not using an explicit (extrenal) Transaction object to govern this.
When you call Commit() on a UoW it commits all actions. Then when you add another actions and call Commit() again, it commits all the newly added actions. Everytime it uses a separate implicit (internal) Transaction, so each Commit() will have nothing to do with the other. unless.
![]()
Unless you use a Transaction object, and pass false to the UoW.Commit() overload which accepts an AutoCommit parameter, in order not to call commit of the external transaction object.
And then after calling UoW.Commit() several times, you call Commit() on the Transaction object to Commit the external transaction.
Dear Walaa I think I am lost some where ! Though the forum rules says not post entire code, in my case I felt it would be prudent to attach full code to clearly understand where I am going wrong. I am really stuck with UOW for long
Or let us look at this small code. If financial year id is 0, it commits event entity but it should not because billcounter is not saved becoz of foreign key violation
private void Savedata() { var adapterevent = new DataAccessAdapter(); try {
int FinancialYearID = MonthlyBill.returnFinancialYearReceipt(string.Format("{0:dd/MMM/yyyy}",
dateeventdate.Value.Date));
string message;
var eventuow = new UnitOfWork2();
var evententity = new EventEntity();
evententity.Description = ChangeCase.ToTitleCase(tbxdescription.Text.Trim());
evententity.Eventdate = dateeventdate.Value;
evententity.Createddate = ServerDateTime.getcurrentserverdatewithtime();
evententity.CreateduserId = StandardMessage.loginuserid;
eventuow.AddForSave(evententity);
var billcountermember = new BillcounterEntity();
evententity.Billcounters.Add(billcountermember);
billcountermember.Billnumber = 0;
billcountermember.FinancialfunctionalyearId = FinancialYearID;
billcountermember.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcountermember.CreateduserId = StandardMessage.loginuserid;
billcountermember.Ismember = GlobalVariable.optionYes;
eventuow.AddForSave(billcountermember);
var billcounterguest = new BillcounterEntity();
evententity.Billcounters.Add(billcounterguest);
billcounterguest.Billnumber = 0;
billcounterguest.FinancialfunctionalyearId = FinancialYearID;
billcounterguest.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcounterguest.CreateduserId = StandardMessage.loginuserid;
billcounterguest.Ismember = GlobalVariable.optionNo;
eventuow.AddForSave(billcounterguest);
eventuow.Commit(adapterevent,true);
{
message = StandardMessage.datasavesuccess;
DoRefresh();
}
MessageBox.Show(message);
}
catch (Exception ex)
{
GlobalErrorHandler.LogMessage(ex.Message + ex.StackTrace);
MessageBox.Show(StandardMessage.datasavefailure);
}
finally
{
adapterevent.CloseConnection();
adapterevent.Dispose();
}
}
Please try the following:
var eventuow = new UnitOfWork2();
var evententity = new EventEntity();
evententity.Description = ChangeCase.ToTitleCase(tbxdescription.Text.Trim());
evententity.Eventdate = dateeventdate.Value;
evententity.Createddate = ServerDateTime.getcurrentserverdatewithtime();
evententity.CreateduserId = StandardMessage.loginuserid;
var billcountermember = new BillcounterEntity();
billcountermember.Billnumber = 0;
billcountermember.FinancialfunctionalyearId = FinancialYearID;
billcountermember.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcountermember.CreateduserId = StandardMessage.loginuserid;
billcountermember.Ismember = GlobalVariable.optionYes;
var billcounterguest = new BillcounterEntity();
billcounterguest.Billnumber = 0;
billcounterguest.FinancialfunctionalyearId = FinancialYearID;
billcounterguest.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcounterguest.CreateduserId = StandardMessage.loginuserid;
billcounterguest.Ismember = GlobalVariable.optionNo;
evententity.Billcounters.Add(billcountermember);
evententity.Billcounters.Add(billcounterguest);
eventuow.AddForSave(evententity, null, false, true);
Joined: 26-Mar-2010
Walaa wrote:
Please try the following:
var eventuow = new UnitOfWork2(); var evententity = new EventEntity(); evententity.Description = ChangeCase.ToTitleCase(tbxdescription.Text.Trim()); evententity.Eventdate = dateeventdate.Value; evententity.Createddate = ServerDateTime.getcurrentserverdatewithtime(); evententity.CreateduserId = StandardMessage.loginuserid; var billcountermember = new BillcounterEntity(); billcountermember.Billnumber = 0; billcountermember.FinancialfunctionalyearId = FinancialYearID; billcountermember.Createddate = ServerDateTime.getcurrentserverdatewithtime(); billcountermember.CreateduserId = StandardMessage.loginuserid; billcountermember.Ismember = GlobalVariable.optionYes; var billcounterguest = new BillcounterEntity(); billcounterguest.Billnumber = 0; billcounterguest.FinancialfunctionalyearId = FinancialYearID; billcounterguest.Createddate = ServerDateTime.getcurrentserverdatewithtime(); billcounterguest.CreateduserId = StandardMessage.loginuserid; billcounterguest.Ismember = GlobalVariable.optionNo; evententity.Billcounters.Add(billcountermember); evententity.Billcounters.Add(billcounterguest); eventuow.AddForSave(evententity, null, false, true);
Altered as suggested but same problem.
If i dont add this eventuow.Commit(adapterevent, true);
Of-course you should add this line. I was just minimizing the post by showing what to change.
You can try the following also:
private void Savedata()
{
var adapterevent = new DataAccessAdapter();
adapterevent .StartTransaction(IsolationLevel.ReadCommitted, "MultipleSaves");// <==========
try
{
int FinancialYearID = MonthlyBill.returnFinancialYearReceipt(string.Format("{0:dd/MMM/yyyy}",
dateeventdate.Value.Date));
string message;
var eventuow = new UnitOfWork2();
var evententity = new EventEntity();
evententity.Description = ChangeCase.ToTitleCase(tbxdescription.Text.Trim());
evententity.Eventdate = dateeventdate.Value;
evententity.Createddate = ServerDateTime.getcurrentserverdatewithtime();
evententity.CreateduserId = StandardMessage.loginuserid;
var billcountermember = new BillcounterEntity();
billcountermember.Billnumber = 0;
billcountermember.FinancialfunctionalyearId = FinancialYearID;
billcountermember.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcountermember.CreateduserId = StandardMessage.loginuserid;
billcountermember.Ismember = GlobalVariable.optionYes;
var billcounterguest = new BillcounterEntity();
billcounterguest.Billnumber = 0;
billcounterguest.FinancialfunctionalyearId = FinancialYearID;
billcounterguest.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcounterguest.CreateduserId = StandardMessage.loginuserid;
billcounterguest.Ismember = GlobalVariable.optionNo;
evententity.Billcounters.Add(billcountermember);
evententity.Billcounters.Add(billcounterguest);
eventuow.AddForSave(evententity, null, false, true);
eventuow.Commit(adapterevent, true);
{
message = StandardMessage.datasavesuccess;
DoRefresh();
}
MessageBox.Show(message);
}
catch (Exception ex)
{
adapterevent.Rollback(); // <=========================
GlobalErrorHandler.LogMessage(ex.Message + ex.StackTrace);
MessageBox.Show(StandardMessage.datasavefailure);
}
finally
{
adapterevent.CloseConnection();
adapterevent.Dispose();
}
}
Joined: 26-Mar-2010
private void Savedata()
{
var adapterevent = new DataAccessAdapter();
adapterevent .StartTransaction(IsolationLevel.ReadCommitted, "MultipleSaves");// <==========
try
{
int FinancialYearID = MonthlyBill.returnFinancialYearReceipt(string.Format("{0:dd/MMM/yyyy}",
dateeventdate.Value.Date));
string message;
var eventuow = new UnitOfWork2();
var evententity = new EventEntity();
evententity.Description = ChangeCase.ToTitleCase(tbxdescription.Text.Trim());
evententity.Eventdate = dateeventdate.Value;
evententity.Createddate = ServerDateTime.getcurrentserverdatewithtime();
evententity.CreateduserId = StandardMessage.loginuserid;
var billcountermember = new BillcounterEntity();
billcountermember.Billnumber = 0;
billcountermember.FinancialfunctionalyearId = FinancialYearID;
billcountermember.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcountermember.CreateduserId = StandardMessage.loginuserid;
billcountermember.Ismember = GlobalVariable.optionYes;
var billcounterguest = new BillcounterEntity();
billcounterguest.Billnumber = 0;
billcounterguest.FinancialfunctionalyearId = FinancialYearID;
billcounterguest.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcounterguest.CreateduserId = StandardMessage.loginuserid;
billcounterguest.Ismember = GlobalVariable.optionNo;
evententity.Billcounters.Add(billcountermember);
evententity.Billcounters.Add(billcounterguest);
eventuow.AddForSave(evententity, null, false, true);
eventuow.Commit(adapterevent, true);
{
message = StandardMessage.datasavesuccess;
DoRefresh();
}
MessageBox.Show(message);
}
catch (Exception ex)
{
adapterevent.Rollback(); // <=========================
GlobalErrorHandler.LogMessage(ex.Message + ex.StackTrace);
MessageBox.Show(StandardMessage.datasavefailure);
}
finally
{
adapterevent.CloseConnection();
adapterevent.Dispose();
}
}
I had indeed added this eventuow.Commit(adapterevent, true);
Joined: 26-Mar-2010
You can try the following also:
private void Savedata()
{
var adapterevent = new DataAccessAdapter();
adapterevent .StartTransaction(IsolationLevel.ReadCommitted, "MultipleSaves");// <==========
try
{
int FinancialYearID = MonthlyBill.returnFinancialYearReceipt(string.Format("{0:dd/MMM/yyyy}",
dateeventdate.Value.Date));
string message;
var eventuow = new UnitOfWork2();
var evententity = new EventEntity();
evententity.Description = ChangeCase.ToTitleCase(tbxdescription.Text.Trim());
evententity.Eventdate = dateeventdate.Value;
evententity.Createddate = ServerDateTime.getcurrentserverdatewithtime();
evententity.CreateduserId = StandardMessage.loginuserid;
var billcountermember = new BillcounterEntity();
billcountermember.Billnumber = 0;
billcountermember.FinancialfunctionalyearId = FinancialYearID;
billcountermember.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcountermember.CreateduserId = StandardMessage.loginuserid;
billcountermember.Ismember = GlobalVariable.optionYes;
var billcounterguest = new BillcounterEntity();
billcounterguest.Billnumber = 0;
billcounterguest.FinancialfunctionalyearId = FinancialYearID;
billcounterguest.Createddate = ServerDateTime.getcurrentserverdatewithtime();
billcounterguest.CreateduserId = StandardMessage.loginuserid;
billcounterguest.Ismember = GlobalVariable.optionNo;
evententity.Billcounters.Add(billcountermember);
evententity.Billcounters.Add(billcounterguest);
eventuow.AddForSave(evententity, null, false, true);
eventuow.Commit(adapterevent, true);
{
message = StandardMessage.datasavesuccess;
DoRefresh();
}
MessageBox.Show(message);
}
catch (Exception ex)
{
adapterevent.Rollback(); // <=========================
GlobalErrorHandler.LogMessage(ex.Message + ex.StackTrace);
MessageBox.Show(StandardMessage.datasavefailure);
}
finally
{
adapterevent.CloseConnection();
adapterevent.Dispose();
}
}
Tried with this revised code as is. Still the same problem. Guess really something serious.
Joined: 26-Mar-2010
Walaa wrote:
Are you sure the FK constraint is enforced in the database?
It seems to me that there is no exception thrown from the database, that's why no Rollback is taking place.
Yes it is.
Log Entry : 04/12/2011 14:28:29 Error Message:An exception was caught during the execution of an action query: ORA-02291: integrity constraint (BCLUB1868.FINFUC_BILLCOUNTER_1) violated - parent key not found . Check InnerException, QueryExecuted and Parameters of this exception to examine the cause of this exception. at SD.LLBLGen.Pro.ORMSupportClasses.ActionQuery.Execute() in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.0\Frameworks\LLBLGen Pro\RuntimeLibraries\ORMSupportClasses\Query\ActionQuery.cs:line 261 at SD.LLBLGen.Pro.ORMSupportClasses.BatchActionQuery.Execute() in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.0\Frameworks\LLBLGen Pro\RuntimeLibraries\ORMSupportClasses\Query\BatchActionQuery.cs:line 112 at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.ExecuteActionQuery(IActionQuery queryToExecute) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.0\Frameworks\LLBLGen Pro\RuntimeLibraries\ORMSupportClasses\AdapterSpecific\DataAccessAdapterBase.cs:line 541 at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.PersistQueue(List`1 queueToPersist, Boolean insertActions, Int32& totalAmountSaved) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.0\Frameworks\LLBLGen Pro\RuntimeLibraries\ORMSupportClasses\AdapterSpecific\DataAccessAdapterBase.cs:line 1453 at SD.LLBLGen.Pro.ORMSupportClasses.UnitOfWork2.Commit(IDataAccessAdapter adapterToUse, Boolean autoCommit) in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.0\Frameworks\LLBLGen Pro\RuntimeLibraries\ORMSupportClasses\UnitOfWork\UnitOfWork2.cs:line 879 at ClubCentric.Master.MasterEvent.Savedata() in D:\Bangalore Club - Software Projects\Under Implementaion\VS Final Solution\ProjectLive\ClubCentric\Master\MasterEvent.cs:line 374
Joined: 26-Mar-2010
Walaa wrote:
So the call reaches the catch block, and indeed call adapter.Rollback() right? But still the entity is not rolled back, correct?
Does the same happens when using the Transaction object alone without using the UoW?
Yes Walaa
Joined: 26-Mar-2010
Walaa wrote:
Does the same happens when using the Transaction object alone without using the UoW?
Yes Walaa
Could you please post a very simple and minimal repro solution based on Northwind?
Can I just give you the two tables structure and sample data ?
Joined: 26-Mar-2010
shekar wrote:
Walaa wrote:
Does the same happens when using the Transaction object alone without using the UoW?
Yes Walaa
Could you please post a very simple and minimal repro solution based on Northwind?
Can I just give you the two tables structure and sample data ?
Please let me know if the attached file is sufficient
Joined: 26-Mar-2010
[quotenick="shekar"]
shekar wrote:
Walaa wrote:
Does the same happens when using the Transaction object alone without using the UoW?
Yes Walaa
Could you please post a very simple and minimal repro solution based on Northwind?
Can I just give you the two tables structure and sample data ?
Attached
Filename | File size | Added on | Approval |
---|---|---|---|
Test Tables.txt | 8,937 | 12-Apr-2011 11:44.11 | Approved |
Joined: 08-Oct-2008
Thanks - but we could really do with the code to make the error happen as well. Please don't think that we are trying to make things awkward for you. The more work you can do up front for us the easier things are! Don't forget you know your code a lot better than we do, it's much easier for you do make it fail than for us
Thanks
Matt
Joined: 26-Mar-2010
MTrinder wrote:
Thanks - but we could really do with the code to make the error happen as well. Please don't think that we are trying to make things awkward for you. The more work you can do up front for us the easier things are! Don't forget you know your code a lot better than we do, it's much easier for you do make it fail than for us
![]()
Thanks
Matt
Dear MTrinder, Thanks for response and I shall wait for the solution. For sure, I have learnt LLBLGen to greater extent and have been successful in many ways. It is only this UOW which causing problem for me since long and I have tried all possible combinations but for no luck. If you see my first post on this, I also tried passing larger value than the column length and it rolls back perfectly OK. But when FK's are violated it does not roll back so I am confident that there is nothing wrong in the code
MSOracle has a bug that when transactions roll back it doesn't roll back properly. See: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=14135
There's a hotfix from Microsoft to install to fix this. If this isn't equal to your problem please let us know.
It's recommended to use ODP.NET however, as Microsoft has deprecated MS Oracle in .net 4.
Joined: 26-Mar-2010
Otis wrote:
MSOracle has a bug that when transactions roll back it doesn't roll back properly. See: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=14135
There's a hotfix from Microsoft to install to fix this. If this isn't equal to your problem please let us know.
It's recommended to use ODP.NET however, as Microsoft has deprecated MS Oracle in .net 4.
Dear Otis, I am aware of this post but my situation is entirely different.
As I stated
- It does roll back when I tried to insert value larger than column value. That indicates no fix is needed and code is also alright.
- Problem occurs only when I pass wrong FK value. Here it does not roll back.
- I also did a test without using LLBLGEN but using MS ORACLE and .NET Framework 2.0 which I am currently using. It works absolutely fine
- I had also done the experiment earlier with the post you had referred. But there was no change
The original user who reported it and found it says:
Seems like after a transaction the flag gets changed to AutoCommit and doesn't change back. The colleague who worked on it said the flag gets set to this value in case of some exception, but he couldn't find out more. Well, everything now works as expected, as far as we can tell right now. We'll send some kind of report about this to MS as well.
The wrong FK is the exception causing problem. Of course it works fine in a normal setup, it only goes wrong in a specific situation, otherwise MS would have fixed it before releasing the code.
Please try the hotfix (link in the thread I linked above).
When you specify true for autocommit on UoW.Commit(), the Commit method will call Rollback(). If autocommit is false, it won't as it assumes it's part of a bigger series of calls, so your outer try/catch has to rollback on the adapter. Your code passes true for autocommit, so the rollback should be called.
However, our code can call Rollback all day, if the ADO.NET provider doesn't handle it properly, it won't work. As you're on .NET 2, you absolutely have to make sure you run the hotfix as the MS Oracle provider is buggy in this area.
Joined: 26-Mar-2010
Otis wrote:
The original user who reported it and found it says:
Seems like after a transaction the flag gets changed to AutoCommit and doesn't change back. The colleague who worked on it said the flag gets set to this value in case of some exception, but he couldn't find out more. Well, everything now works as expected, as far as we can tell right now. We'll send some kind of report about this to MS as well.
The wrong FK is the exception causing problem. Of course it works fine in a normal setup, it only goes wrong in a specific situation, otherwise MS would have fixed it before releasing the code.
Please try the hotfix (link in the thread I linked above).
When you specify true for autocommit on UoW.Commit(), the Commit method will call Rollback(). If autocommit is false, it won't as it assumes it's part of a bigger series of calls, so your outer try/catch has to rollback on the adapter. Your code passes true for autocommit, so the rollback should be called.
However, our code can call Rollback all day, if the ADO.NET provider doesn't handle it properly, it won't work. As you're on .NET 2, you absolutely have to make sure you run the hotfix as the MS Oracle provider is buggy in this area.
Ok. Let me try right away and come back.
http://support.microsoft.com/default.aspx?scid=kb;en-us;958445&sd=rss&spid=8291
You have to install SP2 for .NET 2 first, and if you didn't do that already, you really should.
Joined: 26-Mar-2010
Otis wrote:
http://support.microsoft.com/default.aspx?scid=kb;en-us;958445&sd=rss&spid=8291
You have to install SP2 for .NET 2 first, and if you didn't do that already, you really should.
Well I dont have much words to figure out how can I thank you for your excellent support. My whole project was at stake. Now it works like charm @!
One last question. The code I had originally written, was it ok or do i have to use like how walaa suggested ?