This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi - we are current customers and have been using Lightspeed for couple of years now. I am trying to associate a few different unit of works with the same Transaction object - how can I do that. See the issue is that we have a few different objects , attached to different unit of works and I want to be able to commit all the changes in the same transaction. I used the BeginTransaction() on my first unit of work to get an IDbTransaction but then I don't see how can I "assign" this transaction to the other unit of works. I read your thread on Transactions and I also tried using the TransactionScope object but our DB is oracle so in the notes it mentioned Oracle does not support TransactionScope. Does that mean I can not use TransactionScope if we use Oracle in the background? And my third question which I believe I know the answer to is: If I have a UnitOFWork with a transaction - if I Dispose of the UnitOfWOrk (UnitOFWork.Dispose()) - then the transaction also is disposed of,right? So even if say I use a TransactionScope (say I have a SQL Server DB) with the code below:
Then when the Transaction gets commited the items that belonged to this unit of work will not get commited, is that right? |
|
|
You would need to use a TransactionScope to enlist multiple UnitOfWork instances in the same over-arching transaction, but there are caveats around support for System.Transactions with Oracles ADO.NET provider - see here for some more details: http://docs.oracle.com/html/E1516701/featADO20.htm#CJAEDJII Assuming you are able to use this then the TransactionScope will be the way to go. If not you will probably need to look at implementing a crude two-phase commit where you flag when each UOW is ready to commit and then actually call .Commit() on each transaction in turn. If you call .Dispose() on a UnitOfWork with an uncommitted transaction then yes the transaction will rollback as we call .Dispose() on the IDbTransaction instance. Depending on the implementation of the data provider calling .Complete() on the TransactionScope after this occurs will probably throw an exception :)
|
|
|
Hi Jeremy, thanks for the answer. Based on what you said I decided to keep a list of all the Unit of Works and their transactions. This way only after I called SaveChanges() on each unit of work and made sure it does not throw an exception of any sort I will go ahead and commit the transactions. After each transaction has been committed I can then Dispose of the unit of work that is linked to that transaction. The only outstanding question right now is this: Say there is a validation error(for example I have a Customer with Name and in the model I have defined that Name must be unique). So say I am saving a customer with a name which already exists in the DB. Will unitOfWork.SaveChanges() expose that error (given that it is part of transaction) or will the exception be thrown when I commit the transaction associated with that unit of work? As you can see that is an important detail for me because if the exception is thrown on SaveChanges() I will know that by the time I am committing the transaction my data is valid,otherwise I still run the risk of having a partially committed data. |
|
|
Yes, the work is being done in SaveChanges() so if there are any actual issues around persisting the data then you will know about it when you call SaveChanges(). Validation is also run as part of calling SaveChanges() so any validation exceptions will be raised then.
|
|
|
Hi Jeremy, thank you again for the answer. Unfortunately this solution did not work for me either because we have too many unit of works created and if I don't dispose of each unit of work after processing each entity I end up with an Oracle Error. Anywho! I have another question for you while I am trying to solve this problem. See, the reason why we create a new unit of work for each entity is because in our application we have an import function during which we traverse the entities and save them one at a time. OK. So far so good....but say I have an Entity called Customer and one to Many to an Entity called Orders, so one customer can have many orders. Then what happens is that when I create an Order Entity for example , the minute I say Order.Customer = xyz then the "xyz" Customer gets automatically added to the Unit Of Work. The issue with that is that when I traverse the customer Entity itself,it is already added to the UNitOfWork and I get a Expected One but got 2 exception, hence the many unit of works. The opposite however is not true - for example if I say UNitOfWork.Remove(Order) , that does not remove the Customer from the unit of work. For our purposes there are times when I want a delete operation to remove my entity AND all of it's dependencies. That is the reason why we use so many unit of works to begin with so if I can solve that issue, all the above issues will go away. So My Question is How Can I remove from the Unit Of work an entity and all of its dependencies?Maybe there is a flag that I can set or something like that. Thank you very much in advance Susan |
|
|
Something sounds a bit wrong here. The type of scenario is pretty normal and you would always look to manage it within a single UnitOfWork. Can you elaborate on the "expected 1 but got 2" exception you are seeing? When you perform this assignment you should just be swapping out the existing Customer for xyz. Has xyz been loaded from the current UnitOfWork? If Order has been added to the current UnitOfWork then xyz will also be added to the current UnitOfWork and things will be wired up accordingly in terms of removing it from any existing associations and adding it to the new association. What is the traversal you are performing on xyz that then leads to the exception?
|
|
|
Hi Jeremy, so this is the scenario. We have an XML document which has all our data. Then using this document we "load" the data into our system. So for example I have a node that looks something like that
then further down somewhere in the doc I would have nodes called
So When I am importing there are two steps - first I analyze the data to see if there are any errors - and I don't save it (except for some logs in the DB), then I present a report to the customer of what will be imported and what not and then only after they click Import I actually import the data. So the issue is on that Analysis step. I have a Unit of work and so I use the information in the document and Create a Customer Object. So then I do UnitOfWork.Add(customer) . At the end of my validation of customer I do UnitOfWork.Remove(customer) which also works well. - so far so good Then I go over the Order Nodes in the document which have customer = 123 and convert them from XML to an Order Entity in the same way as customer.(same code) As part of that conversion I need to assign the "order.Customer" property so again look for the customer node in the document (since the sequence is not certain and I can not be sure that the customer has already been created and again I create a customer Entity from the node.) I then assign that newly created Customer to the Order ( I need that for validating the order object) At the end of this operation I have- UnitOfWork.Remove(order) - which does not remove the customer. So at the end of all the traversing if I call UnitOfWork.SaveChanges() - needed to save the log changes, it also saves the Customer to the DB which I would expect not to, since I removed the Order. Thus when I go to do the actual import and want to save the customer I find that I already have one in the DB. Basically that is why we opted to have one unit of work to process each entity - and then we discard it at the end of the analysis traversal. Susan |
|
|
It sounds like you are using SaveChanges() as a means to perform validation (I am unsure if you are doing something additional here - you mentioned needing to save the log changes?). If its just for validation you dont need to call SaveChanges(), you can just test Entity.IsValid for each of your objects to trigger a validation to occur :)
|
|