Warlin Garcia · Feb 13, 2019 go to post

You can remove the Calculated keyword and use a combination of  SqlComputeOnChange and Readonly keywords.

What you accomplish:

- Removing Calculated keyword, makes the column persistent

- Adding SqlComputeOnChange gives you control on when you want the value to be calculated (using %%INSERT or %%UPDATE) and based on which column (don't add any if calc must happen for all inserts regardless of which fields are being inserted).

- Adding Readonly just provides and extra "safety" that the value can't be changed via SQL or Object means.

Property readonlyprop As %String [ ReadOnly, SqlComputeCode = { {*} = {ID}_(+$H)}, SqlComputed, SqlComputeOnChange = %%INSERT ];
Warlin Garcia · May 2, 2019 go to post

One variation to #1 would be to  pass an object. It provides for readability (assuming property names are legible) and would allow for flexibility if you need to add a new parameter in the future (method signature doesn't need to change). 

Warlin Garcia · Jun 3, 2019 go to post

The confusion here is that you created 3 class mappings for a single global (not a good practice) and your understanding is that they're just "views", however the 3 of them are full class/tables with the same properties/ownership of the data. With that in mind, using SQL DROP statement has the same effect for any of the 3 tables/classes  (if DDL were allowed).  As others have pointed out, you can accomplish what you're trying to do with DROP %NODELDATA or by removing the class definition (either from Studio or programatically). 

If you wanted to declare views instead of tables then you need to do so via SQL CREATE VIEW statement.

Warlin Garcia · Jun 24, 2019 go to post

The default value for connection pool size on boot is usually 10. You may want to set this value to 1 or 2 for testing purposes (if using the IRIS community version).

Warlin Garcia · Jun 24, 2019 go to post

Which value did you modify? 

The pool size takes couple values into account.

Which connection pooling are you using? If using default boot one it's Hikari and the value to change should be maximumPoolSize

Warlin Garcia · Nov 6, 2019 go to post

First, thanks for this. It go me up and running pretty fast (as title says!). Couple of things:

- The notes/documentation say that code will be loaded into USER namespace, however it's actually being loaded into IRISAPP (as configured in docckerfiles). 

- The jason.config is pointing to USER namespace so any new files and changes to existing will be actually loaded into USER instead of IRISAPP

- Make sure it's all consistent

- The webapp (irisweb) is missing a config for the directory where to store files. I fixed this by modifying the app in management portal. Need to address the installation file/dockerfile

- Haven't been able to make CSPs flow to the container the same as classes. I'm sure I'm missing something but haven't figured out what yet. Any tips? Maybe I'm placing files in the wrong location? Right now I created a csp/irisweb folder under src folder. 

Warlin Garcia · Nov 6, 2019 go to post

Thank you. I'll check on it. 

Do you have any tips to make csp changes flow in realtime the same as classes do? I've modified the dockerfile to copy the contents of my csp directory into the container, however my edits to CSPs are not flowing realtime which forces me to rebuild the container everytime to get my updates.

Warlin Garcia · Nov 15, 2019 go to post

You can map an Oracle Stored procedure to IRIS method using the SQL Gateway. Once the mapping is done, you can expose it with a service or any other means IRIS provides.

Warlin Garcia · Nov 18, 2019 go to post

It's hard to tell what's wrong without all (or more) details. Are you getting an error? If you're not getting an error, are you passing the correct values (values that should return records)? Also, have you tried creating a very basic stored proc in Oracle (select current_date from dual or something like that) and try to use that from IRIS? The exercise will help you eliminate variables for possible issues.

Warlin Garcia · Dec 19, 2019 go to post

While this is certainly possible, you'd be breaking the "contract". %OnNew() is expected to return a %Status that will be handled by %New().  This means the exception will be thrown by %OnNew()  but %New() won't care about it and still return an object (unless something else prevents it from doing so). 

Warlin Garcia · Dec 24, 2019 go to post

How are you running both scenarios? The error you're getting is mostly a symtom of the Cache JDBC jar not being present in the classpath. When you run locally it may be present in your IDE but it's not being included in your build thus the REST code is failing.

Warlin Garcia · Dec 30, 2019 go to post

What are you referring as invalid column name in this scenario?

Why are you checking with invalid columns in the first place? If you know you can have invalid columns then you'd need to add proper error handling for it. You either check the metadata first for valid columns or add exception handling for it.

As for why %SQL.Statement* classes are preferred is due to the improvements these classes contains in terms of usability and performance when compared with the "legacy" %Library.ResultSet.

Warlin Garcia · Jun 29, 2016 go to post

Out of curiosity, why would you need to have a calculated field for this setup? You can always access the properties on ClassC with the following query

SELECT BRecord->Record->Propx FROM SQLUser.ClassC

Warlin Garcia · Jul 13, 2016 go to post

Parameters being passed to a SOAP operation are also defined as properties in the generated class. In your override method, the "proxy" parameter will have a property matching the name of Obj1 and Obj2 parameters. Given your example the following should work

Method override(proxy As %SOAP.ProxyDescriptor, tag As %String)

{

             ....

            W proxy.Obj1,!

             W proxy.Obj2,!

            ........

}

Warlin Garcia · Oct 17, 2016 go to post

You're on the right track,  however, depending on your needs, always prefer a relationship over a "plain" array/list. One of the biggest benefits is the referential integrity you get "out of the box". 

Warlin Garcia · Jun 7, 2017 go to post

The 3 options yield the "same" results, however, depending on needs, one requires more work on your part than the other. With Relationships, for example, Cache automatically handles all referential integrity for you (foreign keys are automatically generated for you). Whereas the other options don't provide that and you're required (depending on your needs) to code  the referential checks (e.g. declare foreign keys). 

Warlin Garcia · Jun 12, 2017 go to post

I guess it depends on which context you're referring to essential.

If you are working on a pure Cache environment you can probably go without the SQL layer. However, you need SQL to expose data to the world (e.g. reporting tools that can only connect through xDBC layer).

In terms for performance you can always make the case that SQL is slower when compared to direct global access, however SQL provides more "readability" for new (and not so new) developers since SQL is "standard" (or wider spread)  compared to ObjectScript.

My rule is to always chose SQL over direct global access unless the performance requirements can only be met by the latter. 

Warlin Garcia · Jun 13, 2017 go to post

There's no easy way for this (as far as I know) as most of this information is "hardcoded" to be written that way in the methods. 

You can always extend the WebRequest class (and its parents) and modify the methods to write the XML in a single line or however you want. However, this is very tedious and carries a lot of problems with each upgrade. 

Warlin Garcia · Oct 3, 2017 go to post

The easiest way would be to change the definition from list to array. But if you can't do that the next easier thing is to change the STORAGEDEFAULT parameter to 'array'.  Both options will project the collection as a separate SQL table that you can join with.

Warlin Garcia · Jan 11, 2018 go to post

1) The reasons for using both together are purely based on your application's need and design. Some design patterns specify desired visibility of methods for example.

2) Safe depends on the context but it's usually easier to move from a restricted mode to a non-restricted one. Moving methods from private to public shouldn't have any impact on your application (functionality wise). However, the opposite is not true and will require you to modify your code to fix the parts that were accessing previously public methods that are private now. This will also impact clients of your code (API) as they'll face the same challenges with the new restrictions.

Warlin Garcia · Apr 13, 2018 go to post

Not sure exactly what you're trying to do or what problem  you're exactly facing (more details would be helpful) but, assuming you're trying to handle the soap body yourself instead of what the wizard generated then you can create a method to create the body and add the name to the WriteSOAPBodyMethod  property of the client class. It's not recommended to call Cache internal methods in your code. It's better to use any provided "hooks" if available.

Warlin Garcia · Sep 20, 2018 go to post

For Cache/IRIS, the JOURNAL files would be the closest option to CDC. There isn't any "generic" product out there that can read and publish the content on journal files for things like streaming or other uses. You can certainly write something to read and publish/stream the changes but it'll be a customized option. 

Cache/IRIS can do it internally for Cache-to-Cache sync/mirroring so it is possible to follow the same logic for other uses. Maybe check with Intersytems if they have had request lake this before. Either they already have a utility or can help you build one. 

Warlin Garcia · Mar 7, 2019 go to post

I like them in the following order:

1) Class Queries

2) Dynamic Queries

3) Embedded SQL

There was a time when Embedded SQL were way faster than dynamic queries, however I think that's not that different anymore. The readability provided by dynamic queries (especially for people new to Cache) outweighs the performance embedded SQL could provide. Of course each situation is different and maybe your application might benefit greatly from that extra performance.

One "drawback" from embedded SQL is that if it's used within routines you need to [manually] compile those routines when pushing changes for a class/table that is part of the embedded SQL. This is true even if those new changes doesn't directly affect that routine or embedded SQL. Classes are compiled automatically depending on the flags you use when compiling the affected table otherwise you need to [manually] compile them as well.

Warlin Garcia · Aug 15, 2019 go to post

Since you're using ObjectScript you should get the value from the list using something like $LISTGET(CList,i). That should return the correct value without control chars. 

If you still want to use $PIECE then SET CListString = $LISTTOSTRING(CList) and then use the $PIECE on the CListString

Warlin Garcia · Sep 17, 2019 go to post

To add a new header, you need to create a subclass of %SOAP.Header with the property you need. Once you have that then you can add it to the appropriate array e.g.

S myheader = ##class(MyNewHeader).%New()

S myheader.mykeyproperty = <myvalue>

D myservice.HeadersOut.SetAt(myheader,"MyNewHeader")

This is assuming the header is not automatically generated from the XML schema.

Warlin Garcia · Dec 19, 2019 go to post

The error should be in the %objlasterror variable. You would have to check: if %New() returned a new instance, if not then check the value of %objlasterror. Then perform any error handling you'd like to do. 

try/catch doesn't work because %New() doesn't throw any exceptions.