Author Topic: VBScript string match doesn't match (!)  (Read 17902 times)

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
VBScript string match doesn't match (!)
« on: December 02, 2015, 04:35:38 am »
Hi all,

I have a problem with VBScript which has kept me occupied for more than six hours. When I compare two strings as to get a boolean result, I always get false even if the two strings are similar.

I read p from a TaggedValue, and the Local Variable window confirms that p holds the value "Persistent". When I compare (p = "Persistent") I expect to get True as the result (of course), but I get False, over and over and over again.

I tried renaming the variable, I tried to compare against a string constant, and as shown in the image below (notice how the variable p should make a perfect match against the string "Persistent", I also tried restarting EA, and restarting Windows, and... no go.

This drives me crazy.

Has anyone out there experienced something similar? Any ideas about what more to try (I think I tried very much already, including reshuffling code into smaller script files, etc, etc, but nothing seems to help).

This is getting spooky:


The program logic should follow the blue arrow, but it follows the red arrow, which indicates that the script interprets p <> "Persistent". <scratching head>

I make this check several times in the same method, but this error is consistent in all places. :(

// Rolf
« Last Edit: December 02, 2015, 06:06:13 am by Rolf_Lampa »
-- There's always a solution --

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #1 on: December 02, 2015, 05:56:41 am »
Hm, the TV value is an enum (Persistent, Transient). Can that be the problem?

But the value from the TV is a string, so it should match against a string literal. Hm.
-- There's always a solution --

qwerty

  • EA Guru
  • *****
  • Posts: 12819
  • Karma: +366/-295
  • I'm no guru at all
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #2 on: December 02, 2015, 06:16:02 am »
I don't know what the query in your screen shot is derived from. But the query builder does not quote strings. It will print quotes only if they are part of the string.

q.

Geert Bellekens

  • EA Guru
  • *****
  • Posts: 11849
  • Karma: +460/-33
  • Make EA work for YOU!
    • View Profile
    • Enterprise Architect Consultant and Value Added Reseller
Re: VBScript string match doesn't match (!)
« Reply #3 on: December 02, 2015, 07:46:12 am »
I'm guessing the result from GetTaggedValue() is not a string but an object or a var or something.

What happens if you do (just to make sure there isn't something weird about p

Code: [Select]
p = GetTaggedValueValue("VBA.Persistence", cls)
p = "Persistent"
if p = "Persistent then
   msgbox "it worked!"
end if

Geert

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #4 on: December 02, 2015, 04:29:28 pm »
Quote
What happens if you do (just to make sure there isn't something weird about p

Code: [Select]
p = GetTaggedValueValue("VBA.Persistence", cls)
p = "Persistent"
if p = "Persistent then
   msgbox "it worked!"
end if
Geert

Thank you for this hint. I tried this, and it works as expected (now).  But, before I tried your code (I saw your post a bit late) I had already manually "cleaned up" in the database from ALL TaggedValues, so when I then reinstalled the MDG and "synchronized" again, it worked (including your code) as expected. This is the working code I settled for :



So the "spooky" problem is now gone.  But...

[size=14]THE PROBLEM[/size]
... now that I can run the code interpreted as expected, I also could systematically track down an old and deep deep problem with TaggedValues; thair so called Default values.

In short: "Default value", as defined in the Project | Settings | UML Types dialog, does not work.

[size=14]Default values - A Huge Problem[/size]
Before describing the problem in more detail, I'd like to hint EA developers about the scale of the/my problem. The following DB table shows the number of TaggedValues, only for attributes, that needs to be poked on manually before the actual value of the TV becomes accessible via the API :


Yes, your eyes are not lying; 76925 (seventy six thousand nine hundred and twenty five) TaggedValues to poke on, manually.

Is this a problem? Yes, it is a huge problem. And then this was only the Attributes, there are a several thousand more TVs in the other model elements (250 x 15 for classes, a few hundred Connectors, with 2x number of Roles, with ~10 TVs each, and so on.

Drop it!
Anyway, since this project is only in the early development stage, I cleaned them all up as to make a step-for-step reconstruction of the problem as to be able to show these screenshots (I hope EA guys will read this). So I dropped them all:


Wosh! Down the drain they went (and all the other tag-tables as well)

How I defined Defaults
Now, did I define the TaggedValues correctly? Well, I always thought I did so. But just to confirm I haven't missed something, this is how I defined them :


TaggedValue example "[size=12]VBA.VBAName[/size]"[/i]

Problem is, this default value ("<Name>") is not available via the API-attributes of a TaggedValue!
[Edit:] I tested it again, also by creting a new class, but nope, no value is available (so it's not only an "update problem").

Here's the code I use trying to access the Value, or alternatively, the Default Value (or Memo):


Fig. This code works (the "tv" variable is a ByRef out/return value)

Now here's the fact: This code works, but, neither the Value nor the Default Value is there!

Workaround
So is there a workaround? Yes, manually poke on the TaggedValues. But before asking me to do that, look again at the number of TaggedValues to poke on (if it took 2 seconds per TV, it would take one work-week+ to poke them all).

Conclusion
Defining Default values in the UML Types dialog displays in the GUI, but it doesn't work at all udner the hood trying to access then via Api/VBScript.

Redundant definitions
So the only way I have found to make the values accessible via API, except for poking on the TVs, is to define the default values in the Stereotypes in the Profile, like so:


Fig. Redundantly redefining a default value as an "initial value" for the Stereotype.

So I did. I Redundantly redefined default values as "initial values" for the Stereotype, and voila! , now the values become accessible to the code shown above. And below is how the (redundant) definition show up in the t_attributetag table:


OK, now we got data exposed as to become accessible also for the modeller.

More than one problem

Continued : -->
« Last Edit: December 02, 2015, 06:09:55 pm by Rolf_Lampa »
-- There's always a solution --

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #5 on: December 02, 2015, 05:03:50 pm »
(Continued)


More than one problem
But there's more than one problem with this redundant approach. If I use the UML type (TaggedValue) in more than one Stereotype, I need to define this "initial value" once for each one of them! (for example I have different Stereoptypes for Association (vba.aso), Aggregation (vba.aggr) and Composite (vba.comp), plus Class and AssociationClass. Which means that sooner or later you tend to lose consistency, and ultimately, you lose control.

Patience

But if you are patient (very patient) you submit to the arrogance behind not bothering to fix such an annoying problem, not even after several years of complaints about this problem, and eventually you resort to defining the Defaults a little here and a little there, like so (the image shows one Stereotype, out of 5 redundant Stereotype definitions, of the same TaggedValue) :



Reward
But then again, you are rewarded with actually being able to access the values you enter into your EA models. Here's the proof:



Yup, there the Default values finally show up. Now the values are accessible through the code (GetTaggedValueValue) shown in the previous post.

Update Model?
But then comes the next problem; What happens when the model changes (modifications in the TaggedValues)? This is the next nightmare which I posted about a few days ago.

I might have missed something very important, and if so I'm the cause of my own problems. But if this description of how default values work for TaggedValues is correct - and I didn't mention that Connection Roles stores these values in a different format, which add even more complexity - I really think there's reason to make life easier for me as a user of the tool.

Suggestion #1

I'm aware of realities, backwards compatibility etc, but you guys really need to provide with at least one thing, soon, and that is one centralized place to retrieve ("global") Default values from.

The existing approach (entering "initial values" on Stereotype attributes) is still useful, because sometime one actually needs different Default Values in different contexts. For example, I use the same TaggedValue, VBA.FileName (mask), for Interfaces and Classes, but the default value are differnt (I<Name> for Interface, and T<Name> for Classes).

Suggestion #2

The Default value could, in stead of being retrieved from .Notes) have it's own property, for example... [size=11]DefaultValue()[/size]. That would give a mature impression.

This value would always present the "last defined" Default value, for example the "Initial value" defined in a Stereotype, in effect it would "override" any GloballyDefaultValue() defined in the UML Type definition.

Suggestion #3

And it follows, yet another property should be provided for TaggedValues, namely  [size=11]GloballyDefaultValue()[/size] [/color]

Suggestion #4

And of course, these two added properties should (in addition to actually accessing the ("globally" defalut values, as defined in the UML Types) be implemented for all Element types with support for Tagged values, which means:
  • Classes
  • Attributes
  • Operations
  • Connections
  • ConnectionEnds
And, there must be no difference in the API for accessing these TaggedValues. No difference. Preferably even the classtype of the TVs should be the same as to simplify code for traversing models (easier to generalize).

How to manage the TVs in Model Updates is yet another problem, but if the API is made to work, so as to be able to programatically set default values, then one can dump "Model Version Info", which can be modified and then put back again without destroying the manually modified settings, at least not without being aware of it. This doesn't seem to be possible as we speak, but it really must be made possible in order to be useful in "future safe" class models.

OK, that was my 2 cents for now.

// Rolf
« Last Edit: December 02, 2015, 06:02:23 pm by Rolf_Lampa »
-- There's always a solution --

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #6 on: December 02, 2015, 05:23:12 pm »
One more thing:

Me like
I love Enterprise Architect. I really do. It brings me 99% of the way, whenever I design entire MDA Frameworks for "one click" solutions resulting in code which is ready to run.

But, the remaining 1%, that is, the problems related to TaggedValues, is crucial when designing your own MDG Technologies/Frameworks, and thus the problems I described in this thread is at risk of actually being a showstopper (it stopped one of my earlier projects some years ago, but I thought the earlier TV problems had been fixed, I just couldn't believe that they have not... Oh well)

But EA is such a powerful tool on many other ways, apart from the problematic default values of the TaggedValues, and related model updates, so it's worth quite some pain to try to find workarounds. But there's a limit to the added complexity one can accept when designing very complex systems.

Near useful
In any case, I hope the development team realizes the significance of fixing the missing tiny little bits described in this thread, and then EA would be near perfect, really.  
 [smiley=thumbsup.gif]

Best regards from Sweden
// Rolf Lampa
« Last Edit: December 02, 2015, 05:25:14 pm by Rolf_Lampa »
-- There's always a solution --

Geert Bellekens

  • EA Guru
  • *****
  • Posts: 11849
  • Karma: +460/-33
  • Make EA work for YOU!
    • View Profile
    • Enterprise Architect Consultant and Value Added Reseller
Re: VBScript string match doesn't match (!)
« Reply #7 on: December 02, 2015, 08:30:14 pm »
Hi Rolf,

Thanks for the elaborate explanation of the issue and workaround.
I'm sure I'm going to stumble onto the same issue one time or another.

I guess you have already sent a feature request/bug report to Sparx support about this?
In general I found them rather willing to fix issues reported, but sometimes things seem to get out of sight. So reminding them once in a while may help to get your issue to the top of the list again.

Geert


qwerty

  • EA Guru
  • *****
  • Posts: 12819
  • Karma: +366/-295
  • I'm no guru at all
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #8 on: December 02, 2015, 10:08:52 pm »
TL;DR (at least not completely)

Quote
Problem is, this default value ("<Name>") is not available via the API-attributes of a TaggedValue!
[Edit:] I tested it again, also by creting a new class, but nope, no value is available (so it's not only an "update problem").
Well, there is Repository.PropertyTypes which is supposed to return the default TVs and along with that the definition that could be parsed. Now, for the first time ever, I tried using that but it returns a zero count although I had defined an enum. I'll look into that again in an hour or so trying to forget this might might be another EA bug and assuming the issue is sitting in front of the keyboard :P

As a workaround there's t_propertytypes.

q.
« Last Edit: December 02, 2015, 10:12:06 pm by qwerty »

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #9 on: December 03, 2015, 02:41:41 am »
Quote
As a workaround there's t_propertytypes.
I know, the workaround for an dysfunctional API is to not use the API.

But when I suggested that they retrieve the info from  t_propertytypes and name it .GlobalDefaultValue() I also didn't ignore the fact that this "global default" isn't enough when the same TaggedValue default needs to be "overridden" in different contexts (for use of the same TV in different Stereotypes), which is actually supported, which is what I describe in my post.

This last point is, although a workaround for the fact that t_propertytypes doesn't seem to present the Default Values via a functional API, an incredible powerful feature, and not only a "hack".

This "workaround" does in effect provide the TaggedValues with "polymorphism", or sort of.

But the problems involved with that "overrride/polymorphism" part is, OTOH, twofold at least

- first, the info is stored differently for different kinds of TaggedValues (t_attributeTag, t_operationTag, t_objectproperties, not to speak of t_taggedvalues ...).

- second, when the model changes, or the UML Types, then you are... well, lost. And there's no workaround for being lost.

So basically, the info IS present in the system, yes, we all know that, but then it follows that what needs to be done is to provide a functional (industrial strength) API to that very info. Which also supports updating the model over time.

// Rolf
-- There's always a solution --

qwerty

  • EA Guru
  • *****
  • Posts: 12819
  • Karma: +366/-295
  • I'm no guru at all
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #10 on: December 03, 2015, 03:44:30 am »
What can I say, except: sigh :-/

q.

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #11 on: December 03, 2015, 03:58:21 am »
Quote
Thanks for the elaborate explanation of the issue and workaround.
I'm sure I'm going to stumble onto the same issue one time or another.

I guess you have already sent a feature request/bug report to Sparx support about this? ...
Geert
Yes probably, and this workaround is actually useful as a feature, since it provides a mechanism for "polymorphism" for DefaultValues, if ony the API would provide what's already in there, underneath, somewhere.

So, I followed your advice and just a minute ago I posted a suggestion to fix this, in the following post:
http://www.sparxsystems.com/cgi-bin/yabb/YaBB.cgi?num=1449074700/0

I think I will have to try to make a VBScript class as a wrapper for the functionality which really should be provided in the following three functions (pseudo):

Class TRILTaggedValueApi
  • Init(ByRef tv)
    tv.Value()  'when absent, retrieve from the two below, in due order :
  • tv.DefaultValue()
  • tv.GlobalDefaultValue()  '  from t_propertytypes
End Class

[edit]I think I was thinking about something like this before (especially the t_propertytypes/GlobalDefaultValue()), but stumbled on performance. I'm not smart enough to find a performing solution in VBScript for accessing the table values. So if anyone out there feels that (s)he can come up with a script that doesn't take a whole day to traverse my 80.000 something attributes, then I'd be very interested to see how that's done.[/edit]

// Rolf
« Last Edit: December 03, 2015, 04:12:52 am by Rolf_Lampa »
-- There's always a solution --

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #12 on: December 03, 2015, 05:04:53 am »
Code Generation Template Revival
I added to my suggestion to EA (see link in previous post) the fact that another (positive) affect of implementing the Value() property as described, would be that the Code Generation Template system could get a second chance.

The Code Generation Template system suffers seriously from this DefaultValue problem, since it it simply doesn't provide the (default) values, period. That's a showstopper.

So, given that the values of the <element kind>Tag's in CodeGen are actually read from the Value() property, also that problem would be solved.

// Rolf
-- There's always a solution --

Geert Bellekens

  • EA Guru
  • *****
  • Posts: 11849
  • Karma: +460/-33
  • Make EA work for YOU!
    • View Profile
    • Enterprise Architect Consultant and Value Added Reseller
Re: VBScript string match doesn't match (!)
« Reply #13 on: December 03, 2015, 06:12:50 am »
Rolf,

As a temporary workaround I would probably write a script to quickly fill in the default value if no value was filled in, but I agree it would be better if EA did by all by itself.

Regarding the performance issue...

In general I try to limit iterating EA.Collections as much as possible.
So if I need all attributes where a tagged values has a certain value, I use Repository.SQLQuery to get hold of the attribute ID's, and I use Repository.GetAttributeByID to get the attribute object I'm interested in. This avoid iterating EA.Element.Attributes, which is the real performance killer.

If even that strategy is not fast enough I use the nuclear option: Repository.Execute.

In your case for example, filling in the default value for all tagged values that don't have a value, I would definitely use an update query with Repository.Execute.
Something like:

Code: [Select]
dim sqlUpdate
sqlUpdate = "Update t_AttributeTag set value = 'Persistent' where property = 'VBA.Persistence' and value is null"
Repository.Execute sqlUpdate

(replace t_attributeTag with the appropriate tagged values table)

Estimated runtime for updating 80.000 records: 0,75 seconds  8-)

Geert

RIL

  • EA User
  • **
  • Posts: 142
  • Karma: +3/-0
  • -- There's always a solution --
    • View Profile
Re: VBScript string match doesn't match (!)
« Reply #14 on: December 03, 2015, 05:00:32 pm »
Thank you for the SQL hints, I will definitely have use for that approach (although bulk updates like this may have side effects considering the opportunity for "polymorphism" in combination with the PropertyTypes settings).

As a matter of fact,  the last eight dark hours I spent designing a wrapper class which does all the neat things I suggested earlier, that is, "polymorphism" by reading (in this order)

[size=12]Value
Default       ''' from Stereotype, if any
GlobalDefault ''' from PropertyTypes[/size]


And, it basically works (I have some more testing to do though). This is how it works:

1. I have a module attribute holding one instance (Singleton) of the wrapper class which I dubbed to TRILTaggedValueAPIHelper. Implemented as such (using short names for usage):

[size=12] -------------------------------------------------------[/size]
[size=12]
Public Function TagAPI()
    If m_tagapi is Nothing Then
        Set m_tagapi = New TRILTaggedValueAPIHelper
    Set TagAPI = m_tagapi
End Function[/size]


2. On Class_Initialize it reads all the [size=12]Repository.PropertyTypes[/size] and stores them in three internal Dictionaries for fast access to its inner details.

Public
The class TRILTaggedValueAPIHelper exposes two main members:

[size=12] -------------------------------------------------------[/size][size=12]
Value  ''' if empty, traversing Value -> Default ->GlobalDefault
Wrap(aTaggedValue) As TRILTaggedValueAPIHelper[/size]


This delivers exactly what we want if wrapping a TaggedValue, and then reading the published properties.

Usage

Say that you hold of a TaggedValue variable and want to read out some info. To do so,
3. Access the API helper class, and simply read the desired property, like so:

-------------------------------------------------------[size=12]
    Dim s
    ''' Given: A TaggedValue object exist in the variable "tv"
    s = TagAPI.Wrap( tv ).Value[/size]


- That's it!
4. If more readings are needed one can continue using the TagAPI until wrapping another TV, like so:

[size=12]
-------------------------------------------------------
    ''' Given: TagAPI still holds the wrapped tv

    s = TagAPI.Value
    s = TagAPI.Default  ''' ... Already in Value, but anyway
    s = TagAPI.GlobalDefault

    ''' Or more intricate, read from the the EA.PropertyType
    ''' with the same name as the currently wrapped TV!


    s = TagAPI.Detail    ''' (= One property of EA.PropertyType)

    ''' Or ...

    s = TagAPI.Description
[/size]

Notice also that the Value() property from TagAPI will (if TV's value is empty) retrieve any Default value as defined in #1 the corresponding Stereotype, and if no such default value is defined, take it from #2 the Repository.PropertyTypes, like so:

[size=12]
-------------------------------------------------------
    ''' Given: TagAPI still holds the wrapped TV, and the
    ''' internal variable in the wrapper class is tv


Public Property Get Value()
    Dim s
    s = tv.Value
    If s = "" Then
        Value = Default   ''' If empty, it'll get it from GlobalDefault!
    ElseIf s = "<memo>" Then
        Value = tv.Notes
    Else
        Value = s  ''' The value already is in "s"
   End If
End Property

[/size]


And so on. Since the Value is "chained" to retrieve from Default() and GlobalDefault() respectively, if empty (resempling "polymorphism) there's also a second set of similar property names prefixed with "M_" as to provide direct access to the "unmanipulated" source values:

[size=12]TagAPI.M_Value()
TagAPI.M_Default()
TagAPI.M_GlobalDefault()[/size]

Etc.

Conclusion
This helper class works. And from this starting point it can of course be enhanced to include functionality for updates & maintenance of the entire TaggedValue system.

If there's interest in the code, just let me know and I'll publish it (after some more testing) so we can enhance it together.

// Rolf Lampa
« Last Edit: December 04, 2015, 03:07:33 am by Rolf_Lampa »
-- There's always a solution --