On Jan 5, 2012, at 9:52 PM, Bill Farrell wrote:
> Thanks, Jason. I think we got most of this covered. I had a long conversation with Lee and that tidied up all but one of my questions (which I forgot to ask).
>
> After learning a little bit more about the %Save mechanism and how Cache treats locks, a bare-naked %Persistent or %MV.Adaptor class extent is nowhere near adequate. Understand, that in MVBooster, there are *no* fatal errors. Errors are reported, but what you do with them at the app level is your business. The reason behind this is that MVBooster wasn't originally coded with applications in mind, although it has proven to be a great framework upon which to hang app code. The original code base (carried forward) was built with two main goals in mind: keeping TCP/IP communications and phantoms alive. One simply cannot count on Cache (nor any MV system, either) alone to manage record locking and data integrity. With phantom processes that handle TCP/IP communications, one can't do a READ/READU/READL bare. If a lock is encountered, a phantom cannot "hang" forever because some idiot went to lunch halfway through a screen leaving records locked. My framework allows a number of reactions: wait a limited amount of time, return immediately if the record can't be read right away, etc. Phantoms and TCP/IP protocals cannot wait forever; something's gonna break. Rather than cause hangs or aborts *EVER*, errors are quietly returned in standard thread-global error variables.
>
> Any file class that extends MVFileAbstraction inherits careful Read(), ReadU(), ReadL(), ReadN() methods (and ReadV methods as well).
>
> Same goes the other way. There are Write()/WriteU() (and value counterparts). There are often good business reasons NOT to release a lock on a given WRITE. That's what the Pick WRITEU was invented for. I haven't yet heard %Save having the ability to emulate WRITEU. While I wouldn't use that in a communications scenario, I have used it (albeit rarely) in applications. The fact that it exists in the MV world was reason enough for me to include it in MVBooster.
>
> Everything I've read and heard today convinces me that neither Open nor %Save alone is going to accomplish the task at hand. Lee helped me talk through the new SetProperty method until I spotted a mechanism (my duh, the error reporting mechanism already in MVBooster, handily) to catch errors thrown by any Set() method. I'm rockin' now.
>
> Thanks again and best regards,
> Bill
>
>
>
> On Thu, 2012-01-05 at 17:08 -0700, Jason Warner wrote:
>> Bill,
>>
>> I've been following this conversation and some interesting things have come out of it. I will provide some comments from our system where we are pushing more towards object only and moving away from MV files.Now, the relevant remaining questions I have are narrowing down pretty fast:
>>> 1. Who calls %OnBeforeSave?
>>
>> %Save and %OnBeforeSave are inherited from %Persistent. When you call %Save it goes through various steps before even getting to the point of writing to disk. One thing to mention is that if you need to massage the data in any way, %OnBeforeSave is the wrong place to do it. %OnAddToSaveSet is where you need to do things like that. From what I understand %Save calls %OnAddToSaveSet of the current object and all children first. Then, %OnBeforeSave then the actual save happens then %OnAfterSave is called. If any of the these return an error status, the entire transaction is rolled back so nothing winds up on disk.
>>
>>> 2. Where is %Save getting its data from? If I use my abstracted method someObject->Write( optionalKey ) I know that exactly one dynamic array will be written to exactly one file. That's the effect I want, no more and no less. If %Save follows Storage, then I've already got it made and needn't worry with the question any further.
>>
>> %Save gets its data from the properties on the object itself. In and object that inherits from %MV.Adaptor, you can also add additional attributes to the properties that tells how and where it is projected to disk. There is an attribute that you can add to a property that tells the compiler that this property will never be stored to disk (I can't remember what it is). There are other attributes that you can add that specify that a property can only be a certain length or even that it must follow a certain pattern. All of these attributes are checked when %Save is called and a status is returned detailing any violations.
>>
>>> 3. If I use my nifty little SetProperty() method Ed got me started on to find and set a property value (that is, an attribute in the dynamic array held in thisObject->Record), who's checking the data type. If the property's Set() method I call (by inference) rejects either the content or type thus returning an error %Status, where does that status go after the $Xecute? Can I catch it and return it to the mainline that called the custom SetProperty() method?
>>
>> This is an interesting point I ran into when working with %Time variables from MV. If you set a property to time() then the value stored is actually a string. It is treated like a string until it is required to be anything but a string. The information I got from InterSystems at the time is that one of the ways that Cache gets better performance is to not cast anything until it needs to be what it needs to be. Since time() from the MV shell returns a string it stays a string until it has to be a %Time variable.
>>
>> One thing you can do is override the setters and getters for a property on an object to do the checking on the data if it needs to happen before your attributes are evaluated during the %Save routine. One thing to be aware of, is that in older versions of Cache, you can't access i%PropertyName (the internal storage variable for your property).
>>
>> I understand wanting to validate data in a green screen environment at the time it is entered since you control the user's interaction with your application at all times. However, if you are planning to move to the web in the future, you may want to avoid throwing errors when setting properties in favor of validating the data at save. You can't guarantee what order a user will enter data on the web and like the example mentioned earlier, they may know their zip and enter it, but have to look up their address and add it later.
>>
>>> 4. If I set a property as [Required], where does that get caught and would I even need to set a property [Required] if I'm doing sanity checking in %OnBeforeSave()?InterSystems Corporation
>>>
>> [Required] is checked in the %Save function. I don't remember if this happens before or after the %OnBeforeSave, but I do know it happens after the %OnAddToSaveSet. If it was me, I would use [Required] on the property instead of checking in the %OnBeforeSave. It seems to show my intent much more clearly in the code and I feel like %OnBeforeSave is useful for checking more complex data. For example, we have a requirement not to store the unique identifiers for Canadian dealers in our data due to Canadian law. However, in the US, we do want and collect Tax IDs and the like. We have to do these checks in the %OnBeforeSave.
>>
>> As Michael Cohen brought up, the code for SQL and MV triggers are run from different entry points from the %Save data. If you decide to go the %Save route, you should probably do away with your MV triggers and move that code into your %AddToSaveSet, %OnBeforeSave or %OnAfterSave. If you try to keep MV triggers and %Save logic it can get very complicated very fast.
>>
>> Jason
>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
>> To post to this group, send email to
Cac...@googlegroups.com
>> To unsubscribe from this group, send email to
CacheMV-u...@googlegroups.com
>> For more options, visit this group at
http://groups.google.com/group/CacheMV?hl=en
>
> --
> You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
> To post to this group, send email to
Cac...@googlegroups.com
> To unsubscribe from this group, send email to
CacheMV-u...@googlegroups.com
> For more options, visit this group at
http://groups.google.com/group/CacheMV?hl=en
--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to
Cac...@googlegroups.com
To unsubscribe from this group, send email to
CacheMV-u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/CacheMV?hl=en