Open rockfordlhotka opened 2 months ago
I think this is an interesting concept worth discussing on its own, so I've elevated it to be its own issue.
It does make sense to me that a calculated value should:
I have a (?) on point 3, because I can see both sides of this.
On one hand you can imagine a calculated property that is derived by calculations of other properties, and so if they haven't changed, then the calculated value wouldn't change either.
On the other hand, you can imagine a calculated property that is derived by the values of other properties plus something like a date/time or database value - something that changes independent of other object properties. As a result, any time the calculated property is recalculated it would change, even if other properties did not change.
The thing is, that second scenario is what we have today - so a normal property (perhaps marked as NonSerialized) would solve scenario 2.
But we can't really support scenario 1, because all properties feed into the IsSelfDirty behavior today.
I run into scenario one all the time and unless I mistake what you are saying, I don't see it as a problem. Whenever an object is updated from the DataPortal I make sure all rules are run and then I mark the object as "clean" because I know for a fact at this point the relevant attributes are the same as what was fetched. I never serialize those calculated properties (Add them to the ignore list and are not part of my DTOs) and the only way they can create an IsDirty situation is if some other property on the same object I do care about becomes dirty first forcing a recalculation.
The only time I would see this as an issue is a long running asynchronous rule that I wouldn't be able to wait for the result before marking the object as "clean" on a DataPortal operation. But in such cases I'd look for other techniques to handle that business logic.
Doesn't MarkClean() on DataPortal operations already provide the solution in most cases?
To throw in my two cents on this issue. All of our fetch methods have this code in the ObjectFactory class:
// Must mark old before checking rules as some rules could be dependent on new vs. old.
MarkOld(result);
CheckRules(result);
// Some rules can update values, which makes the object appear dirty.
// Another MarkOld will also mark the object clean.
MarkOld(result);
@hurcane fwiw, these days you should try to use await CheckRulesAsync()
when possible so your code is ready for async rules if you use them in the future.
I think the idea of not serializing a property and recalculating it when being deserialized is going to be difficult to design. How would the logic know which rule to run? Would we add an opt-in property on business rules to run after serialization? Would you just run the full CheckRules when deserializing?
I do like the idea of being able to simply exclude a property from being considered in the default IsDirty logic. Maybe a NeverDirty attribute? You could combine that with NonSerialized, or choose to still serialize it but not have to worry about marking the object clean just for the calculation rules.
One area we would use this is with descriptions of identity values. A customer ID is entered on an order and a rule looks up the customer name. If the rule runs again and the name was changed, it doesn't really affect the dirty state of the order, which is still for the same customer ID.
A possible use case: Summary of X other properties. Sending that over the wire is unnecessary due to the sum nature, but I do want to participate in changes of that value to simplify other stuff (Instead of having X input variables I only have to care about 1 in other rules). In the new form this recalculation would always mark the BO as dirty on it's first (re)calculation. That's for a brand new object probably not a problem. X * 0 = 0 (to go with my sum example). But as soon as you load existing data you have the following scenario. All data loaded and because people might do a
CheckRules
before returning from the server to the client the BO is now dirty. The newly calculated value wasn't loaded. Now on the client I recalculate the value and my BO is dirty again. Without doing anything. That seems really weird to me. To prevent that with currently available tools, a developer must useLoadProperty
in it's rules or property defintion. (I'm unsure here if anAddOutValue()
of a rule uses the property set or Set/LoadProperty internally).Or maybe I miss something crucial here? I personally would love to have a property declaration where I can mark the property as "not dirty relevant" so I can use it in rules etc. without interfering in changes made by users.
Originally posted by @StefanOssendorf in https://github.com/MarimerLLC/csla/issues/1628#issuecomment-2327316111