REST easy with kbmMW #9 – Database 4 – Data augmentation and XML

This blog post will focus on one way of augmenting data returned from a database using the ORM, serving this as a wellformed XML result to REST client’s using as little code as possible.

kbmMW’s ORM is pretty good at fetching data from a database based on a class.

Sometimes we want to augment the class with additional data, before returning the data to a client.

This we can use the virtual table attribute for.

An example.

We have a class TPerson, which is used by the ORM to persist and retrieve persons from the person database table.

The person might refer to a company, via a companyId which is a GUID. This is all straight forward.

  [kbmMW_Table('name:person')]
  TPerson = class
  private
     FID:kbmMWNullable<string>;
     FName:kbmMWNullable<string>;
     FCompanyID:kbmMWNullable<string>;
  public
     [kbmMW_Field('name:id, primary:true, generator:shortGUID',ftString,40)]
     property ID:kbmMWNullable<string> read FID write FID;

     [kbmMW_Field('name:name',ftString,50)]
     [kbmMW_NotNull]
     property Name:kbmMWNullable<string> read FName write FName;

     [kbmMW_Field('name:companyId',ftString,40)]
     property CompanyID:kbmMWNullable<string> read FCompanyID write FCompanyID;
  end;

However lets say we want to provide an augmented REST interface to the person information, where we want to add additional fields, like company name.

  [kbmMW_VirtualTable]
  [kbmMW_Root('person',[mwrfIncludePublic])]
  TAugmentedPerson = class
  private
     FID:kbmMWNullable<string>;
     FName:kbmMWNullable<string>;
     FCompanyID:kbmMWNullable<string>;
     FCompanyName:kbmMWNullable<string>;
  public
     [kbmMW_Field('name:id',ftString,40)]
     property ID:kbmMWNullable<string> read FID write FID;

     [kbmMW_Field('name:name',ftString,50)]
     property Name:kbmMWNullable<string> read FName write FName;

     [kbmMW_Field('name:companyId',ftString,40)]
     property CompanyID:kbmMWNullable<string> read FCompanyID write FCompanyID;

     [kbmMW_Field('name:companyName',ftString,50)]
     property CompanyName:kbmMWNullable<string> read FCompanyName write FCompanyName;
  end;

What you can see is that an additional class is defined, which purpose primarely is to marshal augmented TPerson data to REST clients.

We have told that the TAugmentedPerson (which by outset has no relation to TPerson class wise), is a virtual table, which means it does in fact not live in any databases, but it can still be used as the output for queries.

So lets put together an augmented query:

[kbmMW_Service('name:REST, flags:[listed]')]
[kbmMW_Rest('path:/rest')]
TsvcRest = class(TkbmMWCustomHTTPSmartService)
public
   [kbmMW_Rest('method:get, path:persons')]
   function GetPersons:TObjectList<TAugmentedPerson>;
end;
// Return augmented persons.
function TsvcRest.GetPersons:TObjectList<TAugmentedPerson>;
begin
 Result:=dmMain.ORM.QueryList<TAugmentedPerson>('SELECT p.ID as ID, p.Name as Name, '+
           ' CompanyID, c.Name as CompanyName '+
           'FROM uData.TPerson p, uData.TCompany c '+
           'WHERE c.ID=p.Company');
end;

This will make a query, augmenting the person data with a company name and returning it as a JSON object to the REST client.

This is all well and fine.

But lets say that the REST interface wants to return this list of TAugmentedPerson’s as XML?

This is now easily done in kbmMW by adding a responseMimeType to the kbmMW_Rest attribute of the GetPersons method.

[kbmMW_Service('name:REST, flags:[listed]')]
[kbmMW_Rest('path:/rest')]
TsvcRest = class(TkbmMWCustomHTTPSmartService)
public
   [kbmMW_Rest('method:get, path:persons, responseMimeType:application/xml')]
   function GetPersons:TObjectList<TAugmentedPerson>;
end;

This will result in simple XML document representing the resulting list of TAugmentedPerson’s. You can ask kbmMW to add XML declarations, namespaces and types if you want to by adding the properties declared:true, typed:true to the kbmMW_Rest method attribute.

But looking at the XML, it is still not perfect. It’s outer node is called TObjectList<person>, which is not a terribly nice tag name for an XML node. We are missing a way to redefine how kbmMW is to name the TObjectList<TAugmentedPerson> class.

Usually one would use the kbmMW_Root attribute in combination with our own class definition, to specify any name changes to root elements when marshalling data into or out from object instances, similarly to how TAugmentedPerson was defined.

However since we do not define TObjectList<TAugmentedPerson> anywhere (it is implicitely being defined as the result from our ORM.QueryList call, we have no place to specify our settings/attributes for that particular class.

Next version of kbmMW provides a new kbmMW_Alias attribute which handles this issue.

Basically what it does is to declare any class as an attribute wise alias to any other class/classes, like this

[kbmMW_Root('persons',[mwrfIncludePublic])]
[kbmMW_Alias]
TAugmentedPersonList = class(TObjectList<TAugmentedPerson>);

The kbmMW_Alias can have zero or one argument. If an argument is given, it can be a class reference, or an array of class references. If no argument is given, kbmMW automaticallyh defines TAugmentedPersonList to be an alias to TObjectList<TAugmentedPerson> due to the class inheritance.

As we never define TObjectList<TAugmentedPerson> anywhere, we can not refer to it as a class reference, why we use kbmMW’s way to implicitely determine the class by not providing any arguments for the kbmMW_Alias attribute.

In reality we will usually never instantiate any TAugmentedPersonList instances. It is only being used as a “placeholder” for defining attributes (on the class level) on types we don’t directly declare ourselves, like the TObjectList<TAughmentedPerson>.

Now the xml will look pretty, with the outer node named <persons> containing a number of inner nodes named <person> which each of them includes the companyName in addition to other TPerson related data.

As a side note, the  [kbmMW_VirtualTable] attribute can now also take an argument, namely the actual database class for which this class is a virtual class for.

It would be possible to define  [kbmMW_VirtualTable(TPerson)]

It informs kbmMW about that any queries made for TAugmentedPerson (which is not really a table found in the database), where the ORM can not deduce from any kbmMW SQL query statement, where to pickup data from, then it should use TPerson as the goto data table.

So this is now legal:

var
  ap:TAugmentedPerson;
begin
  ap:=ORM.Query<TAugmentedPerson>(['Name'],['Kim']);
end;

It will return first found record in the person table, which matches the person named Kim and return that as a TAugmentedPerson instance.

Only fields matching will be filled. Hence in this case the CompanyName value is null since we did not provide any value for it via the query.

But we are getting an object instance which allows us to add our own value for CompanyName, thus in practice augmenting the TPerson look alike object with additional information.

 

REST easy with kbmMW #8 – Database 3

In previous articles we have seen how easy it is to use kbmMW’s ORM to maintain database structures and access and manipulate data.

Next release of kbmMW continues to extend on the ORM with additional features designed to make typical chores easy.

Most often, you want records to disappear from a table the moment you call ORM’s delete methods.

But sometimes, for example when you are referencing the record from other tables, it would be nice to retain the record silently, but keep it out of the result set of most queries.

Some databases supports this the hard way by using referential integrity, which means you will simply not be allowed to delete the record if some other table reference it.

That leaves it entirely up to the developer to manually manage when to show the record and when not to.

kbmMW’s ORM takes a slightly different approach to the problem. What if you define a field in the class that will flag if the record is to be considered deleted or not, and tell kbmMW that it should take that field into account when operating that particular class?

Next version will allow you to do just that. So instead of actually deleting the record, kbmMW will automatically flag it as deleted, AND automatically keep the record out of the queries result sets, regardless if you use higher level methods to operate the data, or lowerlevel kbmMW SQL statements.

The following is a sample class holding images and other stuff. Notice the kbmMW_Table attribute. It now also contains some new settings:

defaultDeleteMethod:mark
deleteMarkProperty:Default
deleteMarkValue:true

[kbmMW_Table('name:image, defaultDeleteMethod:mark, deleteMarkProperty:Deleted, deleteMarkValue:true')]
TImage = class // this unit is called uData
private
   FID:kbmMWNullable;
   FDescription:kbmMWNullable;
   FPersonID:string;
   FBlob:TMemoryStream;
   FDeleted:boolean;
protected
   procedure SetBlob(AValue:TMemoryStream); virtual;
public
   constructor Create; virtual;
   destructor Destroy; override;

   [kbmMW_Field('name:id, primary:true, generator:shortGuid',ftString,40)]
   [kbmMW_NotNull]
   property ID:kbmMWNullable read FID write FID;

   [kbmMW_Field('name:personid',ftString,40)]
   [kbmMW_NotNull]
   [kbmMW_Null('')]
   property PID:string read FPersonID write FPersonID;

   [kbmMW_Field('name:description',ftString,30)]
   property Description:kbmMWNullable read FDescription write FDescription;

   [kbmMW_Field('name:blob',ftGraphic)]
   [kbmMW_NotNull]
   property Blob:TMemoryStream read FBlob write SetBlob;

   [kbmMW_Field('name:deleted',ftBoolean)]
   property Deleted:boolean read FDeleted write FDeleted;
end;

Default value for defaultDeleteMethod is delete or default which means the same… just delete the record (the usual way).

However when setting it to mark, we tell kbmMW that we want kbmMW to mark the deletion of records by setting the value of a specific field to a specific value. Basically it can be most (non blob) types of field, and the value can also be chosen at will. In our case, we indicates that we want the Deleted boolean property to be the one that indicates if a record is deleted or not.

The moment we use ORM.Delete(…) on an TImage instance, the corresponding record will be marked as deleted, and if we search for TImage instances in the database using ORM, the deleted ones will not be returned to us.

So from the perspective of the developer, the delete seems to operate exactly the same as before, with the big exception, that the records are in fact still available in the table. The ORM just hides the deleted ones from us.

In other situations, you might actually want to delete the record the old fashioned way, but you would like also to have a copy of the deleted record in a backup or audit table.

This can also easily be done in kbmMW by setting defaultDeleteMethod to move.

[kbmMW_Table('name:image, defaultDeleteMethod:move, deleteMoveToTable:uData.TBackupImage')]
TImage = class
...
end;

[kbmMW_Table('name:backupImage')]
TBackupImage=class(TImage)
public
   [kbmMW_Field('name:id, primary:true',ftString,40)]
   [kbmMW_NotNull]
   property ID:kbmMWNullable read FID write FID;
end;

Notice that we also provide a deleteMoveToTable setting, which points to the fully qualified name of the class that should act as the backup/audit table.

Each time we use kbmMW to delete a record, it will first be inserted into the database table named backupImage, and only then be deleted from the image table. All this will run in a single transaction, and if things goes wrong, a rollback will be forced to ensure the consistency between the backup table and the actual table is not violated during the insert/delete operation.

In the above example we have redefined the id field’s attributes, to ensure that there is no generators defined on it. The reason is that using kbmMW’s SQL statements to delete a record will automatically be rewritten to select into and delete. If any generator fields were defined, those would not be populated in such scenario, why kbmMW would raise an exception if generator fields were found. However if you do not use kbmMW’s SQL statements to delete records, its perfectly legal to have additional generator fields in the backup table. Those will then be populated automatically the usual way.

If you really really want to delete a record on a table where the class are using one of these alternative delete methods, you can add an option to make kbmMW just delete the record.

ORM.Delete(o,nil,[mwqoIgnoreDeleteModification]);

 

Assuming o is an instance of uData.TImage, and o is actually to be found in the table, then the record corresponding to o will be deleted from the table the old fashioned way.

The same option can be given to the Query methods, to allow showing a record that otherwise would not be returned, because it was marked as deleted.

If the move method was used, then you will have to query using the TBackupImage class to get to the deleted (but backed up) records.

ANN: kbmMW Professional and Enterprise Edition v. 5.04.40 released!

We are happy to announce v5.04.40 of our popular middleware for Delphi and C++Builder.

If you like kbmMW, please let others know! Share the word!

We strive hard to ensure kbmMW continues to set the bar for what an n-tier product must be capable of in the real world!

This release fixes reported bugs and adds to, or improves on a number of features:

  • Support for Exists fileclient/server method.
  • Improved DEFAULT handling in ADD/MODIFY COLUMN
  • Improved scheduler staging performance
  • Improved REST body support.
  • Lots of improvements.

Please look in the end of this post for a detailed change list.

Professional and Enterprise Edition is available for all with a current active SAU. If your SAU has run out, please visit our shop to extend it with another 12 months.

CodeGear Edition is available for free, but only supports a specific Delphi/Win32 SKU, contains a limited feature set and do not include source.

Please visit https://portal.components4developers.com to download.

—-

kbmMW is the premiere n-tier product for Delphi, C++Builder and FPC on .Net, Win32, Win64, Linux, Java, PHP, Android, IOS, embedded devices, websites, mainframes and more.

Please visit http://www.components4developers.com for more information about kbmMW.

—-

Components4Developers is a company established in 1999 with the purpose of providing high quality development tools for developers and enterprises. The primary focus is on SOA, EAI and systems integration via our flagship product kbmMW.

kbmMW is a portable, highly scalable, high end application server and enterprise architecture integration (EAI) development framework for Win32, ..Net and Linux with clients residing on Win32, .Net, Linux, Unix, Mainframes, Minis, Embedded and many other places. It is currently used as the backbone in hundreds of central systems, in
hospitals, courts, private, industries, offshore industry, finance, telecom, governements, schools, laboratories, rentals, culture institutions, FDA approved medical devices, military and more.

—-

 5.04.40 Dec 12 2017
        New stuff
        =========
        - Updated kbmMWLog.Output... methods to allow more detailed configuration.
        - Added support for DEFAULT in SQL ADD COLUMN and MODIFY COLUMN in kbmMWSQLRewriter.
        - Improved kbmMWSmartServiceUtils to auto convert body to string argument (UTF8 assumed),
           alternatively TArray argument.
        - Added support for Exists in TkbmMWFileClient and similar on FileService.

        Fixes
        =====
        - Fixed kbmMWHTTPSysTransport to correctly handle in memory body.
        - Fixed KeepPartialFileOnException not removing failed file bug in TkbmMWFileClient.
        - Fixed TkbmMWHTTPSmartService not handling autorization attributes correctly.
        - Fixed YAML not respecting quoted :
        - Fixed compilation for XE5/XE6
        - Fixed kbmMWHexStringToInteger when starting with 0x or $
        - Fixed incorrect stopping transport heartbeat when a client disconnects.
        - Updated UNIDAC adapter (thanks to Tom Yu).

       	Changes/minor additions
        =======================
        - Improved performance of TkbmMWScheduler.
        - Various other debug features like optional stack trace on TkbmMWLock timeout and such.

 

kbmMemTable v. 7.77.60 Standard and Professional Edition released

This is a minor release:

  • Changed FindNearest and GotoNearest to find first matching record, rather than last.
    Notice that this change may break existing code behavior. See next line for fix!
  • Added ASearchType:TkbmSearchType argument to FindNearest and GotoNearest default mtstNearestBefore. Set it to mtstNearestAfter to get old behavior.

kbmMemTable is the premier high performance, high functionality in
memory dataset for Delphi and C++Builder with kbmMemTable Professional
topping the scales as being the worlds fastest!

If you have an up to date Service and Update (SAU) subscription, then
you can immediately visit https://portal.components4developers.com to
download the latest kbmMemTable release.

If not, please visit our shop at http://www.components4developers.com
and extend your SAU with another 12 months.

ANN: kbmMW Professional and Enterprise Edition v. 5.04.30 released!

We are happy to announce v5.04.30 of our popular middleware for Delphi and C++Builder.

If you like kbmMW, please let others know! Share the word!

We strive hard to ensure kbmMW continues to set the bar for what an n-tier product must be capable of in the real world!

This release fixes reported bugs and adds a number of new features:

  • Support for DEFAULT column values in ORM.
  • Support for kbmMW_HTTP attribute for http services.
  • Lots of improvements.

Please look in the end of this post for a detailed change list.

Professional and Enterprise Edition is available for all with a current active SAU. If your SAU has run out, please visit our shop to extend it with another 12 months.

CodeGear Edition is available for free, but only supports a specific Delphi/Win32 SKU, contains a limited feature set and do not include source.

Please visit https://portal.components4developers.com to download.

—-

kbmMW is the premiere n-tier product for Delphi, C++Builder and FPC on .Net, Win32, Win64, Linux, Java, PHP, Android, IOS, embedded devices, websites, mainframes and more.

Please visit http://www.components4developers.com for more information about kbmMW.

—-

Components4Developers is a company established in 1999 with the purpose of providing high quality development tools for developers and enterprises. The primary focus is on SOA, EAI and systems integration via our flagship product kbmMW.

kbmMW is a portable, highly scalable, high end application server and enterprise architecture integration (EAI) development framework for Win32, ..Net and Linux with clients residing on Win32, .Net, Linux, Unix, Mainframes, Minis, Embedded and many other places. It is currently used as the backbone in hundreds of central systems, in
hospitals, courts, private, industries, offshore industry, finance, telecom, governements, schools, laboratories, rentals, culture institutions, FDA approved medical devices, military and more.

—-

5.04.30 Nov 19 2017

        Important notes (changes that may break existing code)
        ======================================================
        * Renamed elements of TkbmMWSQLResolverNameCase to 
          (mwncUnaltered,mwncUpper,mwncLower).
          This is a breaking change that require you to open/save all 
          forms/datamodules on which metadata components are placed to avoid 
          property name error issues at runtime.

        New stuff
        =========
        - Added unittest project in Enterprise Edition, testing kbmMWORM, 
          kbmMWDateTime, kbmMWNullable and kbmMWConfiguration. It require 
          DUnitX.
        - Added Default column value support to ORM, kbmMW_Field attribute and 
          metadata/rewriters.
          A Default value is required if the field is declared not null and 
          kbmMW shall upgrade the table storage automatically. Syntax example:
          [kbmMW_Field('name:fld4, unique:true, default:0',ftFloat)]
          [kbmMW_NotNull]
        - Added public List property to TkbmMWServers.
        - Added OnServiceDefinition to TkbmMWServer which is called whenever
          a service definition is created due to registration of a service using 
          AutoRegisterServices.
        - Added protected ProcessCustomAttributes to 
          TkbmMWCustomServiceDefinition. It allows custom service definitions to 
          process attributes upon AutoRegisterServices.
        - Added Multiply operator overload to TkbmMWDateTime.
        - Added ExceptOnPersistError boolean to TkbmMWORM.
          If true, it will throw exceptions if any persist/insert/delete/modify
          fails. Else persist errors are silent.
        - Added overloaded Insert, Delete, Modify and Persist methods to 
          TkbmMWORM that takes additional anonymous AFunction that will be 
          called if persistence fails.
        - Changed ValuesByField procedure on TkbmMWCustomResolver to take 
          additional const AWhat:TkbmMWResolverSetValues which controls which 
          version of the record should have its value set.
        - Changed GetDefAsArray and GetDefAsObject of TkbmMWONObject to take 
          additional argument: const AAutoCreate:boolean = true. If false nil is 
          returned if no array or object is found for the property.
        - Added support for using simplified inline YAML syntax for RTTI 
          settings attributes.
        - Added new kbmMW_HTTP attribute for TkbmMWCustomHTTPSmartService. 
          Syntax:
          [kbmMW_HTTP('accept:[f,...], root:[c:path,...], template:[c,...],
                      mimeTypes:["BIN=application/octet-stream",...],
                      charSets:["DOC=utf-16",...])]
          where f can be unknown, get, put, head, post, delete, trace, connect, 
          options, patch
          c can be html,css,script,media,other each followed by a path
          accept controls which types of operations should be accepted by the 
          service.
          root controls which directory to look for the given resource type.
          template controls if a resource type should be considered a template 
          and thus subject to macro replacement.
          mimeTypes add/overwrites to the existing known mimetypes.
          charSets add/overwrites to the existing charset types. Example:
          [kbmMW_HTTP('accept:[get], root:[media:"c:\someimages", 
            html:"c:\somehtml"]')]
          TMyHTMLService = class(TkbmMWCustomHTTPSmartService)
        - Added properties EnabledFileCategories and EnabledFunctions to 
          TkbmMWHTTPServiceDefinition.
          Controls which functions and file categories the service will handle.
        - Added SimplifiedInline:boolean (default false) property to 
          TkbmMWYAMLStreamer.
          It allows for syntax like this: [ a:b, c:d ] which is not accepted 
          standard YAML syntax.
          Standard YAML would write [ a:{b}, c:{b} ]. Hence simplifiedinline 
          should be used with care if at all, since it is not standard YAML 
          syntax and can have sideeffects.
          But it is good for kbmMW's settings attributes syntax.
        - Added ADenyWrite:boolean property to TkbmMWFilePool.Access method to 
          allow better control over share rights to file handles.
        - Added overloaded HTTPResponseFromFile methods to 
          TkbmMWCustomHTTPService.
          Allows for easily naming file for receiving browser and for deciding 
          if to map file path or not.
        - Added SetResponseFileName to TkbmMWCustomHTTPService to define 
          content-disposition, filename header field.
        - Added public property OnException to TkbmMWCustomClient. If an event
          handler is provided, any exceptions within the request operation of a 
          TkbmMWCustomClient will be catched and forwarded to the eventhandler, 
          else the exception will be thrown as usual.

        Fixes
        =====
        - Fixed TDateTime vs TkbmMWDateTime issues in TkbmMWServer.
        - Fixed kbmMW Database adapter wizard adding missing AOwner argument to 
          API methods.
        - Fixed invalid properties in TkbmMWCustomHTTPService.dfm
        - Fixed warnings in kbmMWPassword, kbmMWHashSHA512, kbmMWHashFNV1A and 
          kbmMWRandom.
        - Fixed MetaExists declaration in DBISAM3 and DBISAM4 adapters.
        - Removed explicit operator overload from TkbmMWDateTime.
        - Fixed ORM UpdateGeneratorFields issue when it was overwriting 
          preassigned value of a field with generator attribute, if any other 
          fields needed auto generator assistance.
        - Fixed UpdateGeneratorFields to handle update statements where original 
          field with generator attribute is null.
        - Fixed WaitRuns bug in TkbmMWScheduler.
        - Fixed too early clearing ChildEvents in TkbmMWScheduler.
        - Fixed a couple of YAML parsing bugs.
        - Fixed raising exception if TkbmMWCustomFileClient errors and no  
          OnAccessException is defined.

       	Changes/minor additions
        =======================
        - Changed so kbmMWGetFileSize do not require file to be exclusively 
          available.
        - Renamed elements of TkbmMWSQLResolverNameCase to 
          (mwncUnaltered,mwncUpper,mwncLower).
          This is a breaking change that require you to open/save all 
          forms/datamodules on which metadata components are placed to avoid 
          property name error issues at runtime.

kbmMemTable v. 7.77.50 Standard and Professional Edition released

This is a minor release, required for kbmMW v. 5.04.30:

  • Added support for DEFAULT column value in SQL CREATE and ALTER TABLE.

kbmMemTable is the premier high performance, high functionality in
memory dataset for Delphi and C++Builder with kbmMemTable Professional
topping the scales as being the worlds fastest!

If you have an up to date Service and Update (SAU) subscription, then
you can immediately visit https://portal.components4developers.com to
download the latest kbmMemTable release.

If not, please visit our shop at http://www.components4developers.com
and extend your SAU with another 12 months.

ANN: kbmMW Professional and Enterprise Edition v. 5.04.20 released!

We are happy to announce v5.04.20 of our popular middleware for Delphi and C++Builder.

If you like kbmMW, please let others know! Share the word!

We strive hard to ensure kbmMW continues to set the bar for what an n-tier product must be capable of in the real world!

This release is primarily bugfix release, but does also contain a number of new things:

  • Support for scheduling multiple parallel child jobs for recurrent runs.
  • XML <> Object Notation conversion improvements
  • kbmMW Configuration improvements

Please look in the end of this post for a detailed change list.

Professional and Enterprise Edition is available for all with a current active SAU. If your SAU has run out, please visit our shop to extend it with another 12 months.

CodeGear Edition is available for free, but only supports a specific Delphi/Win32 SKU, contains a limited feature set and do not include source.

Please visit https://portal.components4developers.com to download.

—-

kbmMW is the premiere n-tier product for Delphi, C++Builder and FPC on .Net, Win32, Win64, Linux, Java, PHP, Android, IOS, embedded devices, websites, mainframes and more.

Please visit http://www.components4developers.com for more information about kbmMW.

—-

Components4Developers is a company established in 1999 with the purpose of providing high quality development tools for developers and enterprises. The primary focus is on SOA, EAI and systems integration via our flagship product kbmMW.

kbmMW is a portable, highly scalable, high end application server and enterprise architecture integration (EAI) development framework for Win32, ..Net and Linux with clients residing on Win32, .Net, Linux, Unix, Mainframes, Minis, Embedded and many other places. It is currently used as the backbone in hundreds of central systems, in
hospitals, courts, private, industries, offshore industry, finance, telecom, governements, schools, laboratories, rentals, culture institutions, FDA approved medical devices, military and more.

—-

5.04.20 Nov 12 2017

New stuff
 =========
 - Added ability to Schedule batches of tasks as one job, similarly as Run.
 Using Schedule, it can be recurrent.

Fixes
 =====
 - Updated several database adapters with various fixes.
 - Fixed error popping up in TkbmMWCustomHashItem when range check is enabled in compiler.
 - Fixed bugs in kbmMWScheduler.
 - Fixed leaks in kbmMWScheduler related to scheduling of batches of tasks.
 - Fixed TkbmMWLockFreeHashArray2.Enum not returning AKey2 value.
 This shows up if one enable the nice debug flag
 KBMMW_MREW_NOTIFY_LONG_LOCKS_DEBUG (generally not to be used in production).
 It ensures that deadlocks due to locking will show up in the Windows monitor
 with exact info about which thread(s) held the lock and the type of lock.
 - Fixed off by one in counting when to GC a service instance resulting
 in leaving one too little left when minimum of instances has been defined.
 - Fixed service GC issue when a service has a very long running operation
 that times out and thus should be removed, resulting in less than
 defined minimum number of instances.
 - Fixed kbmMWMT database adapter's resolver to not require a table name.
 - Fixed TkbmMWConfiguration.

Changes/minor additions
 =======================
 - Updated MT demo to match current kbmMW version.
 - Significantly improved XML SaveToObjectNotation and LoadFromObjectNotation.
 Amongst other s added the following options:
 mwxonoAutoIdentifyArrayElement - Set to include i=IndexNumber of array
 attribute.
 mwxonoReservedNameAsElement - Set to not interpret id and type names but
 instead treat them as elements.
 mwxonoAutoNumberUnnamedArrays - Set to add array level to unnamed arrays.
 If not set, sub array will have same name as parent.
 - Added BSON as storage format for TkbmMWConfiguration.
 - Added Prepare...Storage utility methods to TkbmMWConfiguration to easily
 setup specific storage type.
 - Added kbmMWConfiguration sample.
 - Added SetDateTimeTimeZone to TkbmMWDateTime, which specifically sets a
 datetime with a specific timezone.