How do I force a transaction to end?

Jun 13, 2012 at 1:52 PM

At the end of my controller method, I need the current transaction to be committed as I trigger a remote integration service right after that which expects the data that was manipulated.

I thought this would do it

NakedObjectsContext.ObjectPersistor.EndTransaction ();

But I get this error.

Exception Details: NakedObjects.Core.Persist.TransactionException: No transaction running to end

Then tried this:

NakedObjectsContext.ObjectPersistor.FlushTransaction ();

No error, but also no expected data.

Any thoughts?

I know, I am probably not supposed to be trying to do this. :)

Coordinator
Jun 13, 2012 at 2:04 PM

'But apart from that, Mrs. Lincoln, how did you enjoy the play?'    ;-)

You're right  -  this is not the sort of thing we encourage.  However, and at risk of building up future problems for ourselves ...

NakedObjectsContext.ObjectPersistor.EndTransaction ();  is the right idea, but the reason you got the message you did is probably that you hadn't started a transaction at the same level. So try adding:

NakedObjectsContext.ObjectPersistor.StartTransaction ();

at the beginning of your controller method.

Note: Is your custom controller inheriting from the NakedObjects CustomController  -  or is it native?

Richard

Jun 13, 2012 at 2:09 PM
Thanx. I will try that.
It inherits from NakedObjectsController
Jun 13, 2012 at 2:15 PM
Thanx. That worked. :)

PS What is the Flush for?
Coordinator
Jun 13, 2012 at 2:28 PM

I think that dates back many years  - to before our use of Entity Framework, when we were experimenting with NHibernate .  The idea was that Flush would force things to be written to the database, even though you hadn't committed the transaction (i.e. could still be rolled back again), such that they could be read by another method within the same transaction.

To be honest, we're not sure what effect, if any, Flush has when operating with EF  -  because EF handles all the flushing and there are fewer opporunities (or needs) to intervene.  I'll raise a ticket to investigate this and, if that hypothesis is correct, we'll mark Flush as Obsolete.

Jun 13, 2012 at 2:33 PM
Great. Thanx.
Jun 14, 2012 at 3:03 PM

While this doesn't throw any errors,

NakedObjectsContext.ObjectPersistor.StartTransaction ();

NakedObjectsContext.ObjectPersistor.EndTransaction ();

It doesn't seem to actually commit the transaction either.

I know in SQL Server, if you have nested transactions, things only get committed when the outermost transaction gets committed.

So, if you guys have a transaction around the one I am wrapping my code with, calling EndTransaction actually will have no effect. 

Does this make sense, or am I barking up the wrong tree?

Coordinator
Jun 14, 2012 at 4:07 PM

Yes a nested transaction is only committed when the outermost transaction is ended.

You can test out your theory quite easily - just do two consecutive 'EndTransaction's if the second one does not error "No transaction running to end" then your transaction is nested.

Jun 14, 2012 at 4:21 PM
That's the thing. A second call throws an error saying there is no transaction to end.
So does the first if I don't explicitly start one.

But now I am confused, as the transaction has not yet been committed to the DB right before the end of the controller method.
So if it automatically starts a transaction, why is it not there for me to explicitly end. That was my whole problem to start with.

I need the changes to be committed to the DB explicitly.
Editor
Jun 14, 2012 at 4:25 PM
If I can jump in... if the NO MVC architecture hasn't changed from the old NOF/Java days, then the way this may be working is that the framework collates all the changes during the action (in the UpdateNotifier component), and then once the action has completed (from the domain object's viewpoint), then the framework starts an objectstore xactn, executes the collated commands, and commits.

What the FlushTransaction does - at least did in NOF/Java - was to cause the objectstore xactn to be started early, ie during the action, in order that remaining statements within the action could see the changes in the DB. This is useful if there's a repository call, for example.

Dan

On 14 June 2012 16:21, jfbosch <notifications@codeplex.com> wrote:

From: jfbosch

That's the thing. A second call throws an error saying there is no transaction to end.
So does the first if I don't explicitly start one.

But now I am confused, as the transaction has not yet been committed to the DB right before the end of the controller method.
So if it automatically starts a transaction, why is it not there for me to explicitly end. That was my whole problem to start with.

I need the changes to be committed to the DB explicitly.

Read the full discussion online.

To add a post to this discussion, reply to this email (nakedobjects@discussions.codeplex.com)

To start a new discussion for this project, email nakedobjects@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Coordinator
Jun 14, 2012 at 5:16 PM

Dan,

this is one area where things are quite different now with Entity Framework.

We actually use the EF proxies which are doing the change tracking etc for us. When the transaction commits at the end we just 'saveChanges' on the EF context. 

Jacques,

So something to check is what you're making the changes on - I suggest you check the objects to make sure they're EF proxies (if persistent) or NOF proxies (while transient - the NOF proxy is swapped for a EF proxy when the object is persisted).  It's fairly clear if you look at the runtime type of an object in the debugger  - it will be a generated subtype of your domain type.

 

 

 

 

Editor
Jun 14, 2012 at 6:15 PM
Ah well, there you go... I said it might be different. What you're now doing does make sense.


On 14 June 2012 17:16, scascarini <notifications@codeplex.com> wrote:

From: scascarini

Dan,

this is one area where things are quite different now with Entity Framework.

We actually use the EF proxies which are doing the change tracking etc for us. When the transaction commits at the end we just 'saveChanges' on the EF context.

Jacques,

So something to check is what you're making the changes on - I suggest you check the objects to make sure they're EF proxies (if persistent) or NOF proxies (while transient - the NOF proxy is swapped for a EF proxy when the object is persisted). It's fairly clear if you look at the runtime type of an object in the debugger - it will be a generated subtype of your domain type.

Read the full discussion online.

To add a post to this discussion, reply to this email (nakedobjects@discussions.codeplex.com)

To start a new discussion for this project, email nakedobjects@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Jun 14, 2012 at 6:30 PM

>So something to check is what you're making the changes on - I suggest you check the objects to make sure they're EF proxies (if persistent) or NOF proxies (while transient - the NOF proxy is swapped for a EF proxy when the object is >persisted). It's fairly clear if you look at the runtime type of an object in the debugger - it will be a generated subtype of your domain type.

They are all persistent proxies.

I fail to see how this will help me ensure that the transaction is committed at a specific point.

Editor
Jun 14, 2012 at 6:35 PM
Have you turned on SQL profiler to see what's happening at the db level? Would help figure out the point at which NO MVC talks to the DB - before or after the action.



On 14 June 2012 18:30, jfbosch <notifications@codeplex.com> wrote:

From: jfbosch

>So something to check is what you're making the changes on - I suggest you check the objects to make sure they're EF proxies (if persistent) or NOF proxies (while transient - the NOF proxy is swapped for a EF proxy when the object is >persisted). It's fairly clear if you look at the runtime type of an object in the debugger - it will be a generated subtype of your domain type.

They are all persistent proxies.

I fail to see how this will help me ensure that the transaction is committed at a specific point.

Read the full discussion online.

To add a post to this discussion, reply to this email (nakedobjects@discussions.codeplex.com)

To start a new discussion for this project, email nakedobjects@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Jun 14, 2012 at 7:22 PM
Mmm. I just ran a trace and actually find no begin or commit tran statements.
Strange.
Coordinator
Jun 14, 2012 at 7:43 PM
jfbosch wrote:

>So something to check is what you're making the changes on - I suggest you check the objects to make sure they're EF proxies (if persistent) or NOF proxies (while transient - the NOF proxy is swapped for a EF proxy when the object is >persisted). It's fairly clear if you look at the runtime type of an object in the debugger - it will be a generated subtype of your domain type.

They are all persistent proxies.

I fail to see how this will help me ensure that the transaction is committed at a specific point.

If the objects being changed are not proxied any changes will not be submitted to the database as EF simply isn't aware of them. That would be the same symptoms as the problem you're seeing.

Try turning the logging right up to DEBUG and log a single action to a file. It logs on each 'SaveChanges' and I think records the number of changes saved.

 

 

 

Jun 15, 2012 at 9:10 AM

If the objects being changed are not proxied any changes will not be submitted to the database as EF simply isn't aware of them. That would be the same symptoms as the problem you're seeing.

But then they wouldn't be save to the database at all when the controller action is done.

But they are saved to the database. Just notat the point where I want them to be.

        public ActionResult MyControllerAction ( params )
        {
            try
            {
                // If I don't have this start, the end transaction throws an error.
                NakedObjectsContext.ObjectPersistor.StartTransaction ();

                // Call into the model, making changes.

                NakedObjectsContext.ObjectPersistor.EndTransaction ();
               
                // Here I do the call to the external service that expects the data, but the data is not always there.

                return jsonNetResult;
            }
            catch (Exception ex)
            {
                // This correctly rolls back the transaction if there was an error.
                NakedObjectsContext.ObjectPersistor.AbortTransaction ();
                throw;
            }
        }
        // At this point, after the controller action returns, the data is always in the DB.

 

Coordinator
Jun 15, 2012 at 12:01 PM

Then I'm unclear what is happening here.

You have said you're inheriting from NakedObjectsController. That starts a transaction in 'OnActionExecuting' and ends it in 'OnActionExecuted' both which should be called by the MVC framework. 

I suggest you restructure your code and override OnActionExecuted in your controller. Call the base method which should end the transaction and then add your code that calls to the external service. Take a look at the override of OnActionExecuted in GenericControllerImpl.