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
|
I have attached a repro of an issue that has been plaguing our team's use of "reference data". In the example, the key types to focus on are AccountForecast and AccountInfo. AccountInfo is simulated reference data and a list of these are retrieved on a unit of work and detached and the unit of work is subsequently disposed. These AccountInfo objects are then used when creating and adding AccountForecast objects to a collection in the object model. The AccountForecast type has a member of type AccountInfo that is set to the reference data instance. If more than one of the new AccountForecast objects is then removed from the collection and then SaveChanges is called, validation errors ensue. From my diagnosis, the UnitOfWork on the root object in the graph is being propagated to the AccountInfo instance when the AccountForecast is added to the graph. When the AccountForecast is removed, the unit of work is nullified on the AccountForecast and the related AccountInfo objects, however during SaveChanges, these AccountInfo objects are still hanging around in the identitymap and then the UnitOfWork is propagated to them and their backreference (AccountForecast) causing the AccountForecast instances when had been removed from the object graph to be attempted to be saved in an invalid form. It is interesting to note that this only happens when removing multiple AccountForecast instances from the collection. Removing one is generally agreeable (I am assuming because the unit of work on the Forecast object is not nullified at the moment and observes the delete). Can this be fixed or has this been fixed in a subsequent release? We are using the Enterprise version of LightSpeed 2.2.1229.11836 |
|
|
Hi Aaron, I believe this has been fixed as this runs fine against the current 2.2 nightly (while breaking against the version you are currently targetting). There have been quite a lot of fixes included in the nightlies since the version you are using, so it would be highly recommended to upgrade if thats possible.
Jeremy |
|
|
Jeremy, Thanks for the heads up on the fix. We have started using our upgrade to LightSpeed 3 and this issue seems to be resolved although we are now noticing something else troubling that I hope you can help us with, although I don't think this is new behavior to LS3. I have adapted the repro code from my previous post to exhibit the behavior I'm concerned with. When assigning a non new detached entity to another non new attached entity a query is issued to reload the latter from the database. In situations (and we have several of these in our WPF app) where we have a combobox list of detached reference data entities I am noticing that this is negatively affecting performance when selecting a combo box value as the entire object graph for the entity being assigned to is requeried. Looking at both the LightSpeed trace output and the SQL Server Profiler this query is coming across. |
|
|
bumping this back up the list to get an answer |
|
|
Hi Aaron, The extra queries are being generated because you are attaching the reference objects back to the current UnitOfWork which then causes associated objects to be attached which causes the subsequent queries to load in the state of that data. To avoid this just assign the association by identity rather than object which would avoid triggering any attachment of the reference data objects back to the current unit of work, e.g. hydratedActivity.WorkingForecast.AccountForecasts[0].AccountInfoId = referenceAccounts[1].Id;
Jeremy |
|
|
Jeremy, Is there any alternative to this solution that still works? Your proposed solution implies that we would lose all the benefits of working with reference data as objects. For one, in the example above, the AccountInfo object held by AccountForecasts[0].AccountInfo would not have the right state in any of its other attributes if only the id was assigned. - Aaron |
|
|
Hi Aaron, Just to clarify, assigning the Id is the same as assigning the Entity in terms of persistance (you only persist the Id back to the database) so any later use of this would see LightSpeed loading in the object rather than just the Id. If you need to work with the AccountInfo object in the same UnitOfWork scope however you would need to assign the object and take the hit on the queries. This is because the association back from AccountInfo's to AccountForecast is not eager loaded, so this is what is being loaded in for each case. I had a quick chat with Ivan and he thinks that the updates he made for removing the need for back references from ToMany may be able to be applied in this case (where it is a one to one relationship) so this would probably be a better option for you to have a look at, do you think that would work in this situation for you?
Jeremy |
|
|
Jeremy, Thanks for the clarification. I do think the new feature that Ivan was working on for removing the requirement to always have two way navigability may have some promise here. I am very eager to see those changes and to try them out. If removal of the backreference would also avoid the propagation of the unit of work to the "reference data" object, this would be ideal. Let me know when Ivan's solution is available to try. |
|
|
Hello Aaron, There's a first cut of the one-to-many reference data fix in current nightly builds. I was hoping to do some more testing on it before announcing it but if you're keen then by all means pull it down and take it for a spin -- you will probably find bugs though, so be prepared to back out -- and do of course let us know! The way it works is as follows. Note this is not yet supported in the designer so if you are using the designer you will need to set the association's Generation option to None and implement it in the partial class. 1. In the transactional object class (the Song in your example from the other thread), create an foreign key field, EntityHolder field and association wrapper property in the normal way. 2. Mark the EntityHolder with the new NoReverseAssociationAttribute. 3. In the reference data class (the Category), do NOT create an EntityCollection. 4. Ensure that the reference data class is marked as Cached. This is very important! If the reference data is not cached then you will end up in a WORSE position than when you started (LightSpeed will keep going back to the database for the reference data object). (We may lift this limitation in a future drop if there is a need for it; but since the scenario is reference data, and reference data is a good candidate for caching anyway, we hope this is an acceptable requirement for now.) Here's an example: public class Song : Entity<int> Once again, please treat this feature as experimental for now -- please be patient if you hit problems and of course let us know and we will aim to fix them for you as quickly as possible. |
|