Genexus Extensions SDK - Is there a built in helper to save data locally? - sdk

I Would like to know if the Genexus Extension SDK already implements something to store persistent data locally (KB Independant and per KB), something like PersistentDictionary from ManagedEsent
I know that genexus uses SQL Server to store KB Related information, is there an interface for me to extend that?
I want to save data per genexus instance (locally) and use that data to load my extension config, everytime the users executes Genexus.

We don't use PersistentDictionary. I would advice not to use it, as it's a Windows specific API, and we are trying make everything new cross platform, as part of our journey of making GeneXus BL run on other OS.
There are different options of persistence, depending on the specific details of your scenario.
If you want to store something like configuration settings for your extension, you can use the ConfigurationHelper class located in Artech.Common.Helpers. This class provides read access to the configurations defined in the GeneXus.exe.config file in the GeneXus installation folder, as well as read/write access to the Environment.config file located in %AppData%\GeneXus\GeneXus\<version>\Environment.config. Note this file depends on the current user, and is shared between different GeneXus instances of a same main version.
The ConfigurationHelper class provides operations to read and save settings of basic types string, int and bool.
const string MY_EXTENSION = "MyExtensionSettings";
const string SETTING1 = "Setting1";
const string SETTING1_DEFAULT_VALUE = "This is the default value";
const string SETTING2 = "Setting2";
const int SETTING2_DEFAULT_VALUE = 20;
string setting1Value = ConfigurationHelper.GetUserSetting(MY_EXTENSION, SETTING1, SETTING1_DEFAULT_VALUE);
int setting2Value = ConfigurationHelper.GetUserSetting(MY_EXTENSION, SETTING2, SETTING2_DEFAULT_VALUE);
// Do something and maybe change the setting values
ConfigurationHelper.SetUserSetting(MY_EXTENSION, SETTING1, setting1Value);
ConfigurationHelper.SetUserSetting(MY_EXTENSION, SETTING2, setting2Value);
If you want to store something in a file based on the current opened KB, there's no specific API that'll help you handle the persistence. You can use the properties Location and UserDirectory of the KnowledgeBase class to access the KB location or a directory for the current user under the KB location, but it's up to you the handling of the file. You'll have to decide on the file format (binary or text), file encoding in case of text files, and handle all read and write operations to that file.
We use the kb.UserDirectory path to store non-critical stuff, such as the set of objects that were opened the last time the KB was closed, or the filter values for different dialogs.
In case you'd like to store settings inside the KB, there are plenty of options.
You can add properties to existing objects, KB version or environment. Making it a property doesn't necessary mean you'll have to edit the value in the property grid, although it's usually the way to go.
You can define a new kind of entity. Entities are the basic elements that can be stored in a KB. The entity may be stored depending on the active version of the KB, or may be independent of the current version. Entities can have properties, whose serialization is handled by the property engine, and also can read and store a byte array whose format and content will be handled by you.
You can add a part to an existing object. For instance you may want to add a part to Procedure objects. In order to do this you'll have to extend KBObjectPart, define your part in a BL package, declare that the part composes objects of certain type, and provide an editor for your new part in a UI package. KBObjectPart extends Entity so the serialization of the part is similar as in the previous case. A caveat of this option is that you'll also have to handle how the part content is imported, exported, and compared.
You can add a new kind of object. Objects extend the KBObject class, which extends Entity. Objects are not obliged to have parts (for instance the Folder object doesn't have any). When choosing to provide a new kind of object you have to consider a couple of things, such as:
Do you want to be able to create new instances from the new object dialog?
Will it be shown in the folder view?
Can it be added into modules?
Can it have the same name as other objects of different types?
As a general guideline, if you choose to add a new property, add it to objects, versions, or environments, not parts. Adding properties to parts is not so good for discoverability. Also if you choose to add a new kind of object, even though it inherits from Entity which as mentioned earlier can read and store a byte array, it's preferred to don't use the byte array in KBObject and add a KBObjectPart to it instead. That way the KBObject remains as lightweight as possible, and loading the object definition from the DB remains fast, and the blob content is loaded only when truly needed.
There's no rule of thumb. Depending on the specifics of the scenario, one option may be more suited than others.

Related

CoreData - Where to include reference to object?

I'm in the process of moving over the content library of my iOS app from being purely JSON, to leveraging CoreData.
I've produced my datamodels but have one point that I am unclear about, and was hoping to get the ideal approach:
I understand using CoreData to store entries about my individual pieces of content, but want to understand the "right" way to have my produced class have a property or variable that references a functional object that USES the settings in the CoreData entry.
Basic structure:
InstrumentEntry.xcdatamodeld: Contains settings for individual "instrument" entries
Manual codegen produces Instrument+CoreDataClass and Instrument+CoreDataProperties
Instrument.swift: Defines a class which is responsible for producing audio, receiving events, etc.
So,
In my InstrumentEntry+CoreDataClass.swift, can I simply add something like var actualInstrument: Instrument, or, is this something that I include in the actual Data Model as an Attribute or Property?
OR
Do I create my "actualInstrument" and simply have it READ an entry from the CoreData context, rather than maintaining ownership FROM the CD Entry TO an Instrument object?
Thanks!
My approach is to use the CD entry "InstrumentEntry" to set up the "Instrument"s values.
Read from the InstrumentEntry CD and pass that along to the init() of my Instrument class, which maintains a reference to the CD.

How to create nodes in neo4j with properties defined by a dictionary via neo4jclient in C#

As a complete novice programmer I am trying to populate my neo4j DB with data from heterogeneous sources. For this I am trying to use the Neo4jClient C# API. The heterogeneity of my data comes from a custom, continuously evolving DSL/DSML/metamodel that defines the possible types of elements, i.e. models, thus creating classes for each type would not be ideal.
As I understand, my options are the following:
Have a predefined class for each type of element: This way I can easily serialize my objects that is if all properties are primitive types or arrays/lists.
Have a base class (with a Dictionary to hold properties) that I use as an interface between the models that I'm trying to serialize and neo4j. I've seen an example for this at Can Neo4j store a dictionary in a node?, but I don't understand how to use the converter (defined in the answer) to add a node. Also, I don't see how an int-based dictionary would allow me to store Key-Value pairs where the keys (that are strings) would translate to Property names in neo4j.
Generate a custom query dynamically, as seen at https://github.com/Readify/Neo4jClient/wiki/cypher#manual-queries-highly-discouraged. This is not recommended and possibly is not performant.
Ultimately, what I would like to achieve is to avoid the need to define a separate class for every type of element that I have, but still be able to add properties that are defined by types in my metamodel.
I would also be interested to somehow influencing the serializer to ignore non-compatible properties (similarly to XmlIgnore), so that I would not need to create a separate class for each class that has more than just primitive types.
Thanks,
J
There are 2 problems you're trying to solve - the first is how to program the C# part of this, the second is how to store the solution to the first problem.
At some point you'll need to access this data in your C# code - unless you're going fully dynamic you'll need to have some sort of class structure.
Taking your 3 options:
Please have a look at this question: neo4jclient heterogenous data return which I think covers this scenario.
In that answer, the converter does the work for you, you would create, delete etc as before, the converter just handles the IDictionary instance in that case. The IDictionary<int, string> in the answer is an example, you can use whatever you want, you could use IDictionary<string, string> if you wanted, in fact - in that example, all you'd need to do would be changing the IntString property to be an IDictionary<string,string> and it should just work.
Even if you went down the route of using custom queries (which you really shouldn't need to) you will still need to bring back objects as classes. Nothing changes, it just makes your life a lot harder.
In terms of XmlIgnore - have you tried JsonIgnore?
Alternatively - look at the custom converter and get the non-compatible properties into your DB.

Storing large reference data objects in Drools

I'm looking for a way to store large objects within Drools for long periods of time (i.e. not like facts which are added and removed from within a session).
I've read that Drools works using KnowledgeBases and Sessions (Stateless & Stateful) and that KnowledgeBases contain application knowledge definitions but no runtime data.
In a case where I need to store, for example, a large dictionary (that won't change but will be referenced by more than one successive session), and have objects added to working memory and checked against this dictionary to have rules fired, where would it be best to have this stored?
Does everything just go into working memory (in which case, would I need to load the dictionary into memory each time I open a new session?) or am I just missing a crucial Drools basic principle? Would global variables be a good fix for this?
Not sure how large "large" is (of course there's always a performance tradeoff), but you could also use an inserted object to pull from a database (/cache) and have the rules access the values via method.
when
$y : AnObject (name == "car", lookupPrice > 10000 );
where AnObject.getLookupPrice() is a method that would pull a value out of the cached / stored dictionary.
If the object isn't too big you could codify as well (as an object) and use it the same way.

How to adding new section in INI file using TJvAppIniFileStorage

I have a database application project written in Delphi XE and connected to MySQL Database using dbExpress. I use JVCL grid Components to show the records from the Dataset. It will be more efficiently if I can use another JVCL Components to do the FormStorage.
I've been suggested to use TJvFormStorage and TJvAppIniFileStorage for form storage. I have many forms on this project so I need to adding new section in my INI file to store the form size values but I don't know how to do that using TJvAppIniFileStorage.
The TJvAppIniFileStorage is just providing the DefaultSection() method which means it's just can modify and write into one section only which declared as the default.
Anyone can describe to me how to adding new section using the JVCL's TJvAppIniFileStorage?
Thanks in advance.
Is the TJvFormStorage instance the one that determines in which path of the abstract storage to put the data about this form, with the value of the AppStoragePath property.
You can use the special value '%FORM_NAME%' to determine that path automatically at run-time. The '%FORM_NAME%' is changed for the real .Name property of the form where the component is located, or if it is a frame, a dot list of the frame chain up to the form containing it. That way you can have different instances of the same class saving the info to different paths.
When you're using a TJvAppIniFileStorage instance as the data storage backed to save the form data to a INI file, that path is equivalent to the INI section where the information is stored.
In other words, if you want to store the info of your form in a section called 'MyForm', set that value to the AppStoragePath property of the TjvFormStorage instance in that form.
Use the Source, Luke! ;)
My guess is: It uses Parent.Name or Parent.ClassName to store parameters.
Another point: take in mind several monitors on user's computer. Almost no app takes in mind this case.

Is it possible to implement a own IASKSettingsReader?

I use core-data for saving a dynamic (small) amount of entities. These entities have a property for "Display" and "Push", which i sync with my server for each entity.
Now i want to add InApp-Settings to give the user the possibility, to change these two settings within the core data entity.
Because the behaviour and look should be like the Settings.app, i want to use the InAppSettingsKit-Project for this case.
As i read, this library allows to implement a custom SettingsStore to save the values within core data, but i need to read the entities and settings from core data too. In my opinion, it is not possible to define a own subclassed IASKSettingsReader for use.
The next problem is, that i want to use the plist on top-level to show the main-settings and then my own-store on a sub-level of the settings.
Example:
-> Display Settings (From plist)
--> List of entities with my own reader and store to show toggles
-> Push Settings (From plist)
--> List of entities with my own reader and store to show toggles
-> Version (From plist)
-> About (From plist)
Is it possible to accomplish this goal without writing the whole settings from scratch (Which would be very painful and unflexible)?
Thanks for heading me to the right direction in advance!
------EDIT------
I think a possible solution would be, to save a custom plist in the needed format for InAppSettingsKit on app-start, read them in the sub-menu as source for this childpane, save the settings with a custom SettingsStore into the plist and save the data back to core data in the synchronize method.
What do you think about this approach?
The approach you described sounds reasonable. You'll have to tweak the logic to set the path for the plist, though (-locateSettingsFile:). It should also be possible to write a replacement for IASKSettingsReader to dynamically set the field definitions. Alternatively, you could modify the IASKSettingsReader.dataSource property directly (untested, just an idea).
I have implemented the approach that i described in the edit of the question.
The whole approach works this way:
Updating the data in core data with content from my server
Generate two plist files in InAppSettingsKit-like plist-Files within the InAppSettings.bundle
Implemented a SettingsStoreCoreData SettingsStore. It builds a dictionary with values from core data on init and saves them back to core-data when synchronize is called.
As Ortwin Gentz mentioned, it is possible to write a own IASKSettingsReader. But i think my approach needs less work and i have not to deal with different source types within IASKSettingsKit.

Resources