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
|
Currently, the LightSpeed UnitOfWork may keep a physical database connection open for the length of time that the UnitOfWork is in scope and not disposed. Please consider adding a feature which would allow the UnitOfWork to remain in scope for the purpose of tracking changes but in a state that does not maintain an open DB connection. I mentioned this here as well: https://www.mindscape.co.nz/forums/Post.aspx?ThreadID=2255&PostID=6696 This issue goes to the heart of the very usability of LightSpeed for our team.
|
|
|
Hello Aaron, A prototype implementation of this will be in the 11 September nightly. There are some warts in the API and there are some potential avenues of error that I'd like to close off, but I thought I'd get it out there for you to play with and provide feedback. The UnitOfWork class now exposes a ConnectionStrategy property. (Note this is on the UnitOfWork class, not the IUnitOfWork interface. It is the concrete class, not the interface, which knows about databases. Also note this is marked as EditorBrowsableState.Advanced so may not appear in Intellisense depending on IDE settings.) You can set the ConnectionStrategy in order to override the default "keep the connection open until disposed" strategy. We have *not* supplied a closeable-connection strategy out of the box, but here is the strategy I have used for testing, which you can use as-is or as a sample / baseline: public class CloseableConnectionStrategy : ConnectionStrategy The key thing here is the Connection implementation. UnitOfWork will call Connection whenever it wants to use a connection. (It doesn't cache the returned value.) Here we are just creating a connection if we don't already have one, otherwise just returning the one we have -- exactly the same as the default strategy. (Note the use of LightSpeedContext.DataProviderObjectFactory to create the right type of ADO.NET connection object.) But we have also added a CloseConnection method. UnitOfWork will never call this, but our app code can. That will close the connection; in turn, it means UnitOfWork will get a new connection next time it calls the Connection property. The usage would then be as follows: using (UnitOfWork unitOfWork = (UnitOfWork)(_unitOfWork.Context.CreateUnitOfWork())) Note the highlighted lines. Immediately after getting the UOW from the LightSpeedContext, we set its ConnectionStrategy to be an instance of our CloseableConnectionStrategy. That enables us to force the connection closed after loading the Member. A new connection will be created when LightSpeed needs to load the Member.Comments. In reality of course it is likely that you would do the CloseConnection at the end of significant events such as Form_Load and SaveButton_Click. Be aware that LightSpeed will request the Connection whenever it needs it, e.g. for lazy loads, cascade delete planning, etc. It is up to you to detect when this happens and close the re-created connection if / when required. Now a couple of caveats. First, when you take over the connection strategy, it is up to you to manage e.g. transactions, to ensure that they play nicely with your connection boundaries. Second, when you create a ConnectionStrategy, you must specify the same LightSpeedContext as the UOW you are going to assign it to. This is a wart and the API may change to fix this. Also, if you set the UOW's LightSpeedContext property after setting the ConnectionStrategy, you will need to reset the ConnectionStrategy. Third, there are various avenues for error in assigning connection strategies. E.g. nothing at the moment stops you sharing a ConnectionStrategy across UOWs, or changing the ConnectionStrategy while a connection is open. But these would be Bad Things. Basically you should set the ConnectionStrategy to a new instance as soon as you get the UOW from the LightSpeedContext, before you do anything else with it, and then never touch it again. We may change the API in order to prevent these issues, e.g. changing the ConnectionStrategy property to a hypothetical ConnectionStrategyFactory property. I realise you might also want more notifications from the UnitOfWork so that you can make the strategy smarter about automatically closing connections instead of the app code having to do this manually. Once again, please consider this a prototype for feedback and bug reporting; your input is more than welcome. |
|
|
Hi Ivan. |
|
|
Ivan, I have to hand it to you. This is EXACTLY the kind of solution we were looking for and this is EXACTLY the kind of customer service I've been bragging about on Mindscape's behalf. Our team will be digging into this on the next iteration of our product so I'll be in touch. Thanks again! Awesome stuff! HUGE improvement to the product. |
|
|
The complication is actually kind of deliberate: we don't want people to use this feature casually. Most users don't need to manually close connections, and we don't want to make them think they do by having a big honkin' CloseConnection method in Intellisense. By putting up a small barrier to entry we hope that users will mentally hive it off into "I'll look into that if I ever need it" territory rather than thinking "oh no, another API to remember to call." Obviously we are open to simplifying it for the people who do need it though -- feedback welcome! Anyway, no, I didn't mean you would need to extend UnitOfWork or ConnectionStrategy to manage transactions as well as connections -- all I meant was that now you have the option to close the connection, it is up to you to ensure that you do so in a way that respects other boundaries in your code, specifically transaction boundaries. If you close the connection in the middle of a transaction, we will not warn you or try to save you. So the bits of your (application/repository) code that start and end transactions need to co-operate with the bits of your (application/repository) code that close connections. Given the use case for closing connections, of course, I'm sure this is exactly what you'd be doing anyway! |
|
|
Hi Ivan. Are you able to give me an example of what you are trying to convey re transactions? Sample code block? Cheers |
|
|
It is basically what Marko mentioned -- if you are implementing a custom strategy that allows you to break connections, you had better make sure you do not do so while a transaction is in progress on the connection being dropped, because that will effectively roll back the transaction and cause havoc for any subsequent work that was meant to happen as part of that transaction. That is, all I'm trying to convey is that the ADO.NET rules around transactions and connections still apply: implementing a LightSpeed connection strategy doesn't magically buy your app code exemption from those rules. |
|
|
After finding this post, one of my biggest fear suddenly disappeared. I have a rich application using Windows Forms and I don't use pattern like MVC, MVVM or any other patterns that can gives me nice control over my boudaries when creating and disposing UnitOfWork. For this reason, I have to create a lot of small UnitOfWork that create a lot of connection to the database because each UnitOfWork create his own personnal connection. With the ConnectionStrategy, I can now use my central connection to be use be all of my UnitOfWork.
I have read a lot about how I can use UnitOfWork in rich application using Windows Forms but none of them works for me. I can create a UnitOfWork for each form open in my application because user can open dozen of them if he want. And if I open and close UnitOfWork with each having his own connection, the user action interacting with the database while changing value in controls can dramatically open a lot of connection.
Thank you very much for this great feature. |
|