I'm struggling to reconcile the memory management model of TMS Aurelius with my application's management model. My application have a memory management model for the entity classes where if the class A have a property of type class B, class A is responsible to destroy the instance of class B. At the moment, we don't want to change this. We could use a model where Object Manager would be responsible for managing all instances of objects, but we've tried a similar model in the past where we experienced a nigthmare to manage instances created outside the "Object Manager".
The problems:
1 - TMS Aurelius shares instances in the cache. Consequences: let's assume that I want to edit the customer named "Marco Cantu". I use Object Manager to get the current instance of the customer. The user of my application enter invalid data. I do populate the instance with de data user have entered so i can validate the instance. At this time, despite not having submitted the instance to update in Object Manager, the invalid data is visible in the cache. In this way, all other requests to the customer "Marco Cantu" will return an instance with invalid data. Workaround to overcome this: i invoke the ObjectManager.Evict for all instances i retrieve.
2 - Lets suppose two classes: TCity and TSate. TCity has a "many to one" association with TState. TCity is responsible to destroy the TState instance it holds. Problem: when i retrieve the list of the all California cities through Object Manager, all the cities hold's the reference to the same instance of the California TState. Consequence: when destroying the city list, city #2 raises a "Invalid Pointer Operation" exception due to trying to destroy TSate instance which was already destroyed when city #1 was destroyed. Workaround to overcome this: use a cursor to retrieve list of entities. With the cursor I can iterate through every instance retrieved and "evict" one by one.
3 - When saving an entity instance, the instance become attached to the Object Manager cache, by design. Workaround to overcome this: after submitting the entity instance to saving, i invoke Object Manager's evict method over the instances.
Is there any way to fully disable Object Manager cache? If not, are my workarounds correct?
Currently there is no way to disable object manager cache. Evicting manually like you are doing is one valid option. The other one is setting ObjectManager.OwnsObjects to false. This way the manager will not destroy any object inside of it, and it's up to you to manage memory.
Also having one only a single instance of an entity is desired and by design. That's exactly to allow tracking of changes in an entity, if the manager is flushed, and there are duplicated entities in the manager, it will not know which changes to apply.
It looks like you are not using the manager as a manager - a unit of work to change objects and perform changes. You are using the manager just like a "SQL executer". Maybe just setting the OwnsObjects to false will solve your problem.
Also be aware that you should not keep a manager long-lived: create the manager, "quickly" do the job you need to do, then destroy the manager.
Setting ObjectManager.OwnsObjects is not sufficient in my use case because of the strategy used by ObjectManager when loading objects that have associations. For example, the TCity class is associated with the TState class. In my management model, each TCity instance has its own TState instance and therefore, each instance of the TCity class is responsible for destroying its TState indtance. In ObjectManager, if I retrieve a list of all the cities from the state of Alabama, all TCity instances will be loaded by sharing the same instance for the TState class. So, although ObjectManager no longer destroys classes, when I myself destroy the instances of the TCity I will get memory errors because each TCity instance will be sharing the same instance for TState: when destroying an instance of TCity # 1, it will destroy its TState instance which is the same TState instance of TCity # 2. TCity #2 will hold a reference to a destroyed TState instance.
I do agree.
When using the Object Manager as a manager, what is the correct way to deal with invalid data? In my original example (retrieving a customer for edition), what is the correct way to prevent another requests from retrieving an instance of TCustomer with temporary data?
May i add a feature request for disabling cache or to set "cache adapters" so i can control how the cache tracks the changes and retrieve entities?
Is this a general recomendation or a spefic one to my use case?
I am quite satisfied with the high quality of the framework and its powerfull criteria API. I am just trying to fit memory management models.
We have a intention for a while already to include a TStatelessManager which will not have cache or enforce single instances. This will probably be ideal for you, instead of trying to make changes to the TObjectManager. The current manager is what it is, and the design is fine. It just doesn't fit your model (even though you should maybe use specific classes for Aurelius entities instead of using your own). In summary, a TStatelessManager will probably be your solution, but it's not available yet, unfortunately.