finding the parent transaction scope's TransactionScopeOption in the child transactionscope - transactionscope

In a parent transaction scope, i have the TransactionScopeOption of Required.
Later on in a inner transaction scope, i need to check the TransactionScopeOption of the parent transaction scope.
How is this possible..
Example
Parent : using (TransactionScope transactionScopeParent = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
....
method()
}
method()
{
here i need to check the TransactionScopeOption of this transaction scope's parent one and then set this transaction scope to be having the same TransactionScopeOption.
using (TransactionScope transactionScopeChild = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
}
is this possible.

This is not needed.
If the "parent" TransactionScope is Required, the nested one will be enrolled it the transactions already.
If it isn't, the nested one will not automatically become "required".
The only exception is if you explicitly set the nested TransactionScope to RequiresNew, when a new transaction will start.

Judging from your comments to #Oded's answer, you seem to want
MS SQL connections to participate in System.Transactions.Transactions
MySQL connections to not participate
To get that behavior, you just need to append
AutoEnlist=False;
to your MySQL connection string:
If AutoEnlist is set to true, which is the default, a connection
opened using TransactionScope participates in this scope, it commits
when the scope commits and rolls back if TransactionScope does not
commit. However, this feature is considered security sensitive and
therefore cannot be used in a medium trust environment.

Related

Doctrine: atomic updates and exceptions in a loop

We are migrating a project from a more basic ORM to using Symfony+Doctrine. In the project we have a lot of cron jobs looking like this:
$rows = $someRepository->getRows();
foreach ($rows as $row) {
try {
$db->beginTransaction(); //simple begin transaction in db
//do some handling of data
// Maybe load some other entities and update those
// ...
$db->commit();
} catch (Throwable $t) {
//log error
//clear entity cache
$db->rollback(); //simple rollback in db
}
}
When we did it this way, all changes within the try catch was atomic while it at the same time was possible to recover from an error and continue on the next $row.
In Symfony+Doctrine, I simply cannot figure out how to mimic this behaviour. The recommendation from Doctrine to handle an exception is closing the EntityManager, but how do you recover?
The ORM does this implicitly on flush, so most of the time you can avoid the hassle of doing so on your own.
However, if you want clear demarcation you can still do it explicitly, in a similar manner you did so far.
More reading and examples here: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/transactions-and-concurrency.html
EDIT related to the comment below:
Instead of injecting the manager, you should inject the registry.
After that on catch, you can check if the $em->isOpen(), and call $registry->resetManager() if not.
I suspect this will also reset the unit of work, so you might encounter detached entities. In that case you should do $em->merge();
One thing to note here is that an expection is not considered normal in doctrine, so they are closing the manager because of that. You might think that this is overcompicated - yes it is, because you are working against the philosophy here. Validate your data if you can. Read this section: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/transactions-and-concurrency.html#exception-handling
As for the why: (This is not offical, just based on my knowledge) The managers internal unit of work is a stateful object. When an exception occures during a transaction that state will remain the same, but couln't be persisted to the database. If they let this go that would mean the EM would try to apply all state changes again, and would encounter the same exception again. So no point in leaving it open in the same state, a reset is needed.

Datastore: Saving entity with successors in the same transaction with autogenerated key Ids

I'd like to run the following algorithm (it's more like javascript pseudocode)
const transaction = datastore.transaction();
await transaction.run();
const parentKey = createKey(namespace, kind) // note that I leave the ID th be generated
await transaction.save(ancestorKey, parentEntity);
const childKey = createKey(namepsace, kind, parentId, parentKind) // ???
await transaction.save (ChildKey, childEntity);
await transaction.commit();
How can I know the parentId since the initial save of parentEntity is not yet commited?
I'd like to run this into a single transaction, is this achievable?
No, this is not possible due to the datastore's transaction isolation and consistency (emphasis mine):
This consistent snapshot view also extends to reads after writes
inside transactions. Unlike with most databases, queries and gets
inside a Cloud Datastore transaction do not see the results of
previous writes inside that transaction. Specifically, if an entity is
modified or deleted within a transaction, a query or lookup returns
the original version of the entity as of the beginning of the
transaction, or nothing if the entity did not exist then.
Depending on why you actually need such sequence to be done transactionally you might be able to achieve something somehow equivalent this way:
create the parent transactionally
in the same transaction also create and transactionally enqueue a push task queue passing it the parent's key as parameter - the task will be enqueued only if/when the transaction succeeds
in the task handler (also made transactional) create the child entity - guaranteed to only happen once
Note that not all GAE environments support such scheme due to limited push task queue support.

Correct way to use MagicalRecord in a concurrent NSOperation (MagicalRecord-2.3)

With MR_contextForCurrentThread not being safe for Operations (and being deprecated), Im trying to ensure I understand the best pattern for series of read/writes in a concurrent operations.
It's been advised to use saveWithBlock for storing new records, and presumably deletion, which provides a context for use. The Count and fetch methods can be given a context, but still use MR_contextForCurrentThread by default.
Is the safest pattern to obtain a context using [NSManagedObjectContext MR_context] at the start of the operation, and use it for all actions. The operation depends on some async work, but not long running. Then perform a MR_saveToPersistentStoreWithCompletion when the operation is finished?
What's the reason for using an NSOperation? There are two options here:
Use MagicalRecord's background saving blocks:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
// Do your task for the background thread here
}];
The other option is (as you've already tried) to bundle it up into an NSOperation. Yes, I would cache an instance of a private queue context using [NSManagedObjectContext MR_newContext] (sorry, I deprecated the MR_context method this afternoon in favour of a clearer alternative). Be aware that unless you manually merge changes from other contexts, the private queue context that you create will be a snapshot of the parent context at the point in time that you created it. Generally that's not a problem for short running background tasks.
Managed Object Contexts are really lightweight and cheap to create — whenever you're about to do work on any thread other than the main thread, just initialise and use a new context. It keeps things simple. Personally, I favour the + saveWithBlock: and associated methods — they're just simple.
Hope that helps!
You can't use saveWithBlock from multiple threads (concurrent NSOperations) if you want to:
rely on create by primary attribute feature of Magical Record
rely on automatic establishment of relationships (which relies on primary attribute)
manually fetch/MR_find objects and do save based on result of it
This is because whenever you use saveWithBlock new local context created, so that multiple context created in the same time and they don't know about changes in each other. As Tony mentioned localContext is a snapshot of rootContext and changes goes only in one direction, from localContext to rootContext, but not vice versa.
Here is thread-save (or even consistency-safe in terms of MagicalRecord) method that synchronizes calls to saveWithBlock:
#implementation MagicalRecord (MyActions)
+ (void) my_saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
{
static dispatch_semaphore_t semaphore;
static dispatch_once_t once;
dispatch_once(&once, ^{
semaphore = dispatch_semaphore_create(1);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[MagicalRecord saveWithBlock:block
completion:^(BOOL success, NSError *error) {
dispatch_semaphore_signal(semaphore);
if (completion){
completion(success, error);
}
}];
});
}
#end

PetaPoco transaction not rolling back

Maybe this is a really noob question since I'm fairly new to handling transactions with PetaPoco.
Problem I'm facing using PetaPoco as a microORM to handle my db transaction is that if I throw an exception just before the .Complete() method of the transaction, everything is rolled back correctly but if I'm catching exceptions inside the
Using scope As PetaPoco.Transaction = db.GetTransaction()
' try/catch here and if the db command fails transaction won't roll back
scope.Complete()
End Using
the transaction won't roll back if one of the db operations fails. How can I solve this?
The issue was me not handling correctly the "call/not call" the scope.Complete() based on Exceptions intercepted along the path.
In particulart I had a boolean flag "rollBackTransaction" starting to false and then updating to true if any of the try/catch block inside the transaction raised and exception.
At the end I just checked it:
If Not rollBackTransaction Then
scope.Complete()
End If
This can be used as well for the TransactionScope suggested by Simon wich will eventually roll back a transaction if .Complete() is not called before closing the Using block.
Now what was causing a false flag and thus calling the scope.Complete() method each time, was that inside the transaction I called a sub wich had it's own exception handling and thus would never raise an exception in the main transaction block to correctly update the "rollBackTransaction" flag.
What I learned is that if you are using try/catch inside the transaction, be very sure that the external methods you call raise an exception if they fall, and update a flag all along based on wich you will call the scope.Complete().
Anyway Simon, thanks for pointing out that .NET feature I didn't know wich seems to be extremely useful!
Wonder what else it will include in the transaction... file system changes?

Flush separate Castle ActiveRecord Transaction, and refresh object in another Transaction

I've got all of my ASP.NET requests wrapped in a Session and a Transaction that gets commited only at the very end of the request.
At some point during execution of the request, I would like to insert an object and make it visible to other potential threads - i.e. split the insertion into a new transaction, commit that transaction, and move on.
The reason is that the request in question hits an API that then chain hits another one of my pages (near-synchronously) to let me know that it processed, and thus double submits a transaction record, because the original request had not yet finished, and thus not committed the transaction record.
So I've tried wrapping the insertion code with a new SessionScope, TransactionScope(TransactionMode.New), combination of both, flushing everything manually, etc.
However, when I call Refresh on the object I'm still getting the old object state.
Here's some code sample for what I'm seeing:
Post outsidePost = Post.Find(id); // status of this post is Status.Old
using (TransactionScope transaction = new TransactionScope(TransactionMode.New))
{
Post p = Post.Find(id);
p.Status = Status.New; // new status set here
p.Update();
SessionScope.Current.Flush();
transaction.Flush();
transaction.VoteCommit();
}
outsidePost.Refresh();
// refresh doesn't get the new status, status is still Status.Old
Any suggestions, ideas, and comments are appreciated!
I've had a similar problem before, related to isolation levels. The default isolation level was set to "Snapshot", and when running on SQL Server, this meant that the first transaction would not see anything that changed since it started. Maybe it's your isolation level?
If not, try creating a brand-new TransactionScope straight after disposing the one above, and see if you can read it back as New. If you can't, it's probably nothing to do with the outside transaction.
Hope that helps.
Marcus

Resources