lock when loading objects that are being updated

Posts   
 
    
peljam
User
Posts: 6
Joined: 28-Jan-2009
# Posted on: 28-Jan-2009 02:50:37   

I realize this is similar to this thread:

http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=13214

So I am aware of what the problem is, however I am just looking for an alternative to the code I have now. So right now I have some code like this(which is failing)

CustomerEntity entity = new CustomerEntity(ID);

This code is being called after the entity with this ID has been updated in some previous unrelated method(in a Transaction). This causes a lock as there is no way(using the constructor) to tell it to use the transaction to load the entity by ID.

I can not get to this entity without loading it again from the database, but I have access to the same transaction so I could do something like this:

CustomerCollection collection = new CustomerCollection() Transaction.Add(collection); collection.GetMulti(CustomerFields.CustomerID == ID); CustomerEntity entity = collection[0];

This will work as it is now being retrieved within the same transaction. However this seems like a lot of code. Is there a better way to write this? It would be a lot easier if there was something like:

CustomerEntity entity = new CustomerEntity(ID,Transaction);

Is there a way I can use the first method and have it automatically subscribe to a transaction? It would be great if there was a way to force any and all Entities and collections to use a transaction started globally. TransactionScope would obviously solve this issue however in this project I cannot use TransactionScope unless there is a way to prevent it from elevating the transactions(I.e. prevent it from involving the DTC). The DTC cannot be enabled due to configuration restrictions ,firewall, etc.

Any ideas or suggestions would be most appreciated!

Thanks!

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 28-Jan-2009 11:01:01   

CustomerEntity entity = new CustomerEntity(ID);

This code is being called after the entity with this ID has been updated in some previous unrelated method(in a Transaction). This causes a lock as there is no way(using the constructor) to tell it to use the transaction to load the entity by ID.

Was that Transaction Committed? Does the previous method exist in another thread?

If you want to share a transaction, then you'd better use the Adapter model, as then you can start a Transaction in a DataAccessAdapter instance and pass this instance around.

peljam
User
Posts: 6
Joined: 28-Jan-2009
# Posted on: 28-Jan-2009 20:23:11   

Thanks for the quick response!

It would be tough to switch to the adapter model at this point as all of our code(in a 150+ table project) is using the self-servicing model. It's only now though that we realized that we can't use TransactionScope(in the production environment), and have to instead rely on another method for transactioning.

To answer your questions both updates are in the same thread, however the transaction is only commited after the same entity has been updated twice from two different locations in the code.

Both updates look very similar. Something like:

CustomerEntity entity = new CustomerEntity(ID); GlobalTransaction.Add(entity);

//change some entity values

entity.Save();

This syntax will work for the first time through because the entity hasn't been locked yet. However the second time through it will lock on the first line: If it could make it through two itereations it would call GlobalTransaction.Commit(). They both run in the same thread, but completely different sections of code that don't have access to the same instantiation of the customer entity. They both do have access to the same global transaction. This is why the second block of code I described in the first post will work...it's just very verbose.

I have no issue sharing the transaction, as this is what I'm doing now. So in other words I know the solution, but it just seems really complicated to me. It seems like I have to explicitly enlist every single entity and collection in the shared transaction. Also from my understanding what was once done in one line of code now has to be done in 4(as I can no longer use the constructor/ID syntax). I was hoping there was a way to implicitly enlist all entities and collections in a global transaction. Or perhaps I am overlooking something and it can be a lot simpler.

Of course it would be a LOT simpler if I could just use DTC and TransactionScope, but this isn't the case. It's almost like I need a LLBLGen version of the TransactionScope class, which causes all entities and collections to check for a global running transaction and automatically enlist.

Unfortunately I don't have a lot of time to go experimenting with this idea, as maybe I could change the templates to work this way. I've also read somewhere that people are overriding the default behavior of the TransactionScope somehow to not elevate transactions, but again I'd need to do a lot of testing to make sure this this was really working. I work in a government contract and it would tough to get approval for something that is not a standard and proven approach.

Any suggestions would be most appreciate!

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 29-Jan-2009 11:13:22   

One work around is to use the same instance of CustomerEntity, you can achieve this by using a Context which will make sure one unique instance is only available.