<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Efficy Overflow Q&amp;A - Recent questions tagged dataset</title>
<link>https://overflow.efficy.io/?qa=tag/dataset</link>
<description>Powered by Question2Answer</description>
<item>
<title>Is it better to &quot;openEditContextRelation&quot; or &quot;TDataSet.edit() / TDataSet.post()&quot; ?</title>
<link>https://overflow.efficy.io/?qa=4356/better-openeditcontextrelation-tdataset-edit-tdataset-post</link>
<description>&lt;p&gt;Hello, &lt;/p&gt;

&lt;p&gt;Let's imagine I need to mass update the quantity of the products linked to a document.&lt;/p&gt;

&lt;p&gt;Would it be better to do : &lt;br&gt;
&lt;strong&gt;The &quot;openEditContextRelation&quot; method&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var dsProducts = Efficy.getDetailDataSet(docuCtx, ntProd);
            if(dsProducts.isEmpty()) return;

            dsProducts.first();

while (!dsProducts.eof()) {

                var docuProdCtx = Efficy.openEditContextRelation(ntDocu, ntProd, this.k_document, dsProducts.fieldByName('K_PRODUCT').asFloat, dsProducts.fieldByName('K_RELATION').asFloat)
                try {

                    var dsDocuProd = Efficy.getMasterDataSet(docuProdCtx, 0);
                    dsDocuProd.edit();

                    dsDocuProd.fieldByName('QUANTITY').asInteger = -1;
                    dsDocuProd.fieldByName('TOTAL').asFloat = - dsProducts.fieldByName('TOTAL').asFloat;
                    dsDocuProd.fieldByName('F_TOTAL_TVAC').asFloat = - dsProducts.fieldByName('F_TOTAL_TVAC').asFloat;

                    if(dsProducts.fieldByName('F_ISTIMESHEET').asInteger) {
                        this.Time.lockManagement(dsProducts.fieldByName('F_EXT_KEY').asFloat, 1, 0);
                    }

                    Efficy.commitChanges(docuProdCtx, false);

                } finally {
                   Efficy.closeContext(docuProdCtx)
                }

            }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or the &lt;strong&gt;TDataSet.edit() / TDataSet.post()&lt;/strong&gt; ( &lt;strong&gt;&lt;em&gt;My personal choice&lt;/em&gt;&lt;/strong&gt; )&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var dsProducts = Efficy.getDetailDataSet(docuCtx, ntProd);
            if(dsProducts.isEmpty()) return;

            dsProducts.first();

            while (!dsProducts.eof()) {

                dsProducts.edit();

                dsProducts.fieldByName('QUANTITY').asInteger = -1;
                dsProducts.fieldByName('TOTAL').asFloat = - dsProducts.fieldByName('TOTAL').asFloat;
                dsProducts.fieldByName('F_TOTAL_TVAC').asFloat = - dsProducts.fieldByName('F_TOTAL_TVAC').asFloat;

                if(dsProducts.fieldByName('F_ISTIMESHEET').asInteger) {
                    this.Time.lockManagement(dsProducts.fieldByName('F_EXT_KEY').asFloat, 1, 0);
                }

                dsProducts.post();
                dsProducts.next();

            }
// this operation end with a commit on docuCtx and a closeContext
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I never saw the second choice anywhere, in the old project I manage. Is it really a good idea ? I found more convinient to use the &lt;code&gt;TDataSet.edit()&lt;/code&gt; / &lt;code&gt;TDataSet.post()&lt;/code&gt; method, because you don't need to commit at each iteration; &lt;/p&gt;

&lt;p&gt;Thanks in advance, &lt;/p&gt;

&lt;p&gt;Loïc&lt;/p&gt;
</description>
<category>WorkFlow / Serverscript</category>
<guid isPermaLink="true">https://overflow.efficy.io/?qa=4356/better-openeditcontextrelation-tdataset-edit-tdataset-post</guid>
<pubDate>Sat, 25 May 2019 19:36:06 +0000</pubDate>
</item>
<item>
<title>Get only what's change during the edit context</title>
<link>https://overflow.efficy.io/?qa=4023/get-only-whats-change-during-the-edit-context</link>
<description>&lt;p&gt;Hello Efficy Team, &lt;/p&gt;

&lt;p&gt;I got a complex process where I need to &lt;em&gt;do something&lt;/em&gt; with the &quot;new element&quot; of a detailDataSet, or the deleted elements of the detailDataSet during the edit context.&lt;/p&gt;

&lt;p&gt;What is the best way retrieve only those element ? &lt;/p&gt;

&lt;p&gt;Here is what I did : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    var k_project = Efficy.getEditKey(editHandle);
var relationTable = Efficy.entityCatalog.getRelationEntityTableName(ntProj, TEntityHandle);
var kElement = Efficy.entityCatalog.keyFieldName(TEntityHandle);

var dsDetails = Efficy.sqlQueryDataSet('select * from ' + relationTable + ' where k_project = :param1', k_project, 45);
var newDetails = Efficy.getDetailDataSet(editHandle, TEntityHandle);

var changesInTheEditContext = [];

if(dsDetails || !dsDetails.isEmpty()) {

    // the project is already committed. We need to get only the &quot;new&quot; one
    // for that, we filter the &quot;new one&quot; based on the &quot;old one&quot;

    var existing = [];
    dsDetails.first();
    while (!dsDetails.eof()) {
        existing.push(dsDetails.fieldByName(kElement).asFloat);
        dsDetails.next();
    }

    // ho yeah it is ugly. But seems that &quot;not in ()&quot; does not work
    newDetails.filter = kElement +' &amp;lt;&amp;gt; ' + existing.join(' AND ' +  kElement +  ' &amp;lt;&amp;gt; ');
    newDetails.FilterOptions = existing.length;
    newDetails.Filtered = true;

}

// then we get, for each &quot;new one&quot;, useful information's : entity, key, name

if(newDetails.isEmpty() || !newDetails) return false;
newDetails.first();

while(!newDetails.eof()) {

    changesInTheEditContext.push({
        entity : Efficy.entityCatalog.getEntityName(TEntityHandle),
        key : newDetails.fieldByName(kElement).asFloat,
        name : getName(newDetails.fieldByName(kElement).asFloat, TEntityHandle),
        operation : 'add'
    })

    newDetails.next();
}

newDetails.Filtered = false;

// we also need to detect the opposite : a contact deleted during the edit context
// we use the same ticks, but in the opposite (current detailDataSet filter the SQL)

if(dsDetails || !dsDetails.isEmpty()) {

    var fromRelationTable = [];

    newDetails.first();
    while (!newDetails.eof()) {

        fromRelationTable.push(newDetails.fieldByName(kElement).asFloat);
        newDetails.next();

    }

    // ho yeah it is ugly. But seems that &quot;not in ()&quot; does not work
    dsDetails.filter = kElement +' &amp;lt;&amp;gt; ' + fromRelationTable.join(' AND ' +  kElement +  ' &amp;lt;&amp;gt; ');
    dsDetails.FilterOptions = fromRelationTable.length;
    dsDetails.Filtered = true;

    if(dsDetails.isEmpty() || !dsDetails) return false;
    dsDetails.first();

    while(!dsDetails.eof()) {

        changesInTheEditContext.push({
            entity : Efficy.entityCatalog.getEntityName(TEntityHandle),
            key : dsDetails.fieldByName(kElement).asFloat,
            // name : getName(newDetails.fieldByName(kElement).asFloat, TEntityHandle), -- we don't need the name, he's already displayed
            operation : 'delete'
        })

        dsDetails.next();
    }

    dsDetails.Filtered = true;

}

return changesInTheEditContext;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Is there, by any chance, a way to get those change in a more &quot;Efficy way&quot; than comparing two dataSet ? &lt;/p&gt;

&lt;p&gt;Regards,&lt;/p&gt;

&lt;p&gt;Loïc&lt;/p&gt;
</description>
<category>WorkFlow / Serverscript</category>
<guid isPermaLink="true">https://overflow.efficy.io/?qa=4023/get-only-whats-change-during-the-edit-context</guid>
<pubDate>Tue, 12 Mar 2019 07:49:17 +0000</pubDate>
</item>
<item>
<title>get the result of a select statement to an array of object</title>
<link>https://overflow.efficy.io/?qa=2924/get-the-result-of-a-select-statement-to-an-array-of-object</link>
<description>&lt;p&gt;Dear developper community &lt;/p&gt;

&lt;p&gt;Just before Kristof tells me why it's not good^^ let s take a minute to celebrate my new Achievement : I finally found a way to convert Dataset to Array of Objects in javascript. please note that this is the result of delphi Recordset objects researches on the web plus lot of tests.&lt;/p&gt;

&lt;p&gt;I give you the result of my code as a tribute for the great Efficy developpers community^^.&lt;/p&gt;

&lt;p&gt;this is how it works : in my example I try to get &lt;code&gt;all the STATUS_FR and K_OPPO_STATUS from the LK_OPPO_STATUS table ENALBED and with K_OPPO_STATUS lesser than 5&lt;/code&gt;&lt;br&gt;
do you remember doing something like this : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var
    result = new Array(),
    qh = 0,
    context = Database.OpenTemporaryContext(),
    sql = &quot;select * from &amp;lt;#TABLE NAME=LK_OPPO_STATUS&amp;gt; where DISABLED = :param1 and K_OPPO_STATUS &amp;lt; :param2&quot;,
    params = [0, 5].join(&quot;\n&quot;),
    ds = Database.ExecuteSystemSQLQuery(qh, context, sql, params, true, true, 1);

while (!ds.EoF){

    result.push({
        status: ds.FieldByName(&quot;STATUS&quot;).AsString,
        k_oppo_status: ds.FieldByName(&quot;K_OPPO_STATUS&quot;).AsFloat      
    });

    ds.Next();
}

return result; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;that gave you : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[  
   {  
      &quot;status_fr&quot;:&quot;01. Prise de contact&quot;,
      &quot;k_oppo_status&quot;:1
   },
   {  
      &quot;status_fr&quot;:&quot;02. Qualification&quot;,
      &quot;k_oppo_status&quot;:2
   },
   {  
      &quot;status_fr&quot;:&quot;03. Démonstration&quot;,
      &quot;k_oppo_status&quot;:3
   },
   {  
      &quot;status_fr&quot;:&quot;04. Offre&quot;,
      &quot;k_oppo_status&quot;:4
   }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this time my friends is over! now you can do : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;return jsonSelectSQL(&quot;select * from &amp;lt;#TABLE NAME=LK_OPPO_STATUS&amp;gt; where DISABLED = :param1 and K_OPPO_STATUS &amp;lt; :param2&quot;, 0, 5);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note that at this point YOU don't need to specify anything about the fields names or number of fields.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;which will give you something like &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[  
   {  
      &quot;k_oppo_status&quot;:1,
      &quot;k_sort&quot;:1,
      &quot;k_label&quot;:0,
      &quot;status&quot;:&quot;01. Initial Contact&quot;,
      &quot;disabled&quot;:&quot;0&quot;,
      &quot;status_fr&quot;:&quot;01. Prise de contact&quot;,
      &quot;status_nl&quot;:&quot;01. Prise de contact&quot;,
      &quot;status_es&quot;:&quot;01. Prise de contact&quot;,
      &quot;status_de&quot;:&quot;01. Prise de contact&quot;,
      &quot;status_ja&quot;:&quot;&quot;,
      &quot;status_pl&quot;:&quot;&quot;,
      &quot;status_tr&quot;:&quot;&quot;,
      &quot;status_ar&quot;:&quot;&quot;,
      &quot;f_pending&quot;:1
   },
   {  
      &quot;k_oppo_status&quot;:2,
      &quot;k_sort&quot;:2,
      &quot;k_label&quot;:0,
      &quot;status&quot;:&quot;02. Qualification&quot;,
      &quot;disabled&quot;:&quot;0&quot;,
      &quot;status_fr&quot;:&quot;02. Qualification&quot;,
      &quot;status_nl&quot;:&quot;02. Accroche&quot;,
      &quot;status_es&quot;:&quot;02. Accroche&quot;,
      &quot;status_de&quot;:&quot;02. Accroche&quot;,
      &quot;status_ja&quot;:&quot;&quot;,
      &quot;status_pl&quot;:&quot;&quot;,
      &quot;status_tr&quot;:&quot;&quot;,
      &quot;status_ar&quot;:&quot;&quot;,
      &quot;f_pending&quot;:1
   },
   {  
      &quot;k_oppo_status&quot;:3,
      &quot;k_sort&quot;:3,
      &quot;k_label&quot;:0,
      &quot;status&quot;:&quot;03. Démonstration&quot;,
      &quot;disabled&quot;:&quot;0&quot;,
      &quot;status_fr&quot;:&quot;03. Démonstration&quot;,
      &quot;status_nl&quot;:&quot;03. Démonstration&quot;,
      &quot;status_es&quot;:&quot;03. Démonstration&quot;,
      &quot;status_de&quot;:&quot;03. Démonstration&quot;,
      &quot;status_ja&quot;:&quot;&quot;,
      &quot;status_pl&quot;:&quot;&quot;,
      &quot;status_tr&quot;:&quot;&quot;,
      &quot;status_ar&quot;:&quot;&quot;,
      &quot;f_pending&quot;:1
   },
   {  
      &quot;k_oppo_status&quot;:4,
      &quot;k_sort&quot;:4,
      &quot;k_label&quot;:0,
      &quot;status&quot;:&quot;04. Offre&quot;,
      &quot;disabled&quot;:&quot;0&quot;,
      &quot;status_fr&quot;:&quot;04. Offre&quot;,
      &quot;status_nl&quot;:&quot;04. Offre&quot;,
      &quot;status_es&quot;:&quot;04. Offre&quot;,
      &quot;status_de&quot;:&quot;04. Offre&quot;,
      &quot;status_ja&quot;:&quot;&quot;,
      &quot;status_pl&quot;:&quot;&quot;,
      &quot;status_tr&quot;:&quot;&quot;,
      &quot;status_ar&quot;:&quot;&quot;,
      &quot;f_pending&quot;:1
   }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;note that if you strictly want the same result as before you can do : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;return jsonSelectSQL(&quot;select STATUS_FR, K_OPPO_STATUS from &amp;lt;#TABLE NAME=LK_OPPO_STATUS&amp;gt; where DISABLED = :param1 and K_OPPO_STATUS &amp;lt; :param2&quot;, 0, 5);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this is the code of jsonSelectSQL : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function jsonSelectSQL(){

    var 
        ds = selectSQL.apply(null, arguments),
        result = new Array(),
        fields = new Array();

    ds.First();
    if (!ds.EoF) {
        for (var i=0; i&amp;lt;ds.Fields.count; i++){
            fields.push(ds.Fields(i).FieldName);
        }
    }
    while (!ds.EoF){
        var obj = {};

        for (var i=0; i&amp;lt;fields.length; i++) {
            var temp = ds.FieldByName(fields[i]).Value;
            switch(typeof(temp)){
                case &quot;string&quot;:
                    obj[fields[i].toLowerCase()] = temp;
                    break;
                case &quot;number&quot;: 
                    obj[fields[i].toLowerCase()] = Number(temp);
                    break;
                default: 
                    obj[fields[i].toLowerCase()] = temp;
                    break;
            }
        }
        result.push(obj);

        ds.Next();
    }
    return result;
}   
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;please note that you will need this code as well : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;//------(simple closure to don't have to remember which StoreId to use)
var nextStoreId = (function(){
    var storeId = 0;
    return function(){return storeId += 1;};
})();

//------(call this with sql string and parameters and you will get the standard dataset)
function selectSQL(){
    var 
        args = arrayFrom(arguments),
        qh = 0, 
        context = Database.OpenTemporaryContext(),
        sql = args[0],
        params = args.splice(0,1),
        ds = Database.ExecuteSystemSQLQuery(qh, context, sql, params.join(&quot;\n&quot;), true, true, nextStoreId());

    return ds;
}

//-----(convert the classic arguments arraylike object as a regular javascript array)
function arrayFrom(_arg){

    var result = new Array();

    for (var i=0; i&amp;lt;_arg.length; i++){
        result.push(_arg[i]);
    }

    return result;
}   

//-----(home made splice prototype polyfill, feel free to use yours)
Array.prototype.splice = function(){
    var args = arguments;

    var result = new Array();
    var i = 0;

    if (args[0] + args[1] &amp;gt; this.length) throw new Error(&quot;custom Splice error, invalid parameters for this array&quot;);
    while (i &amp;lt; args[0]){
        result.push(this[i]);
        i++;
    }

    if (args[2])    for (var j=0; j&amp;lt;args[2].length; j++) result.push(args[2][j]);

    i = args[0] + args[1];

    while (i&amp;lt;this.length){
        result.push(this[i]);
        i++;
    }

    for (i=0; i&amp;lt;this.length; i++) this[i] = undefined;
    this.length = 0;
    for (i=0; i&amp;lt;result.length; i++) this.push(result[i]);

    return this;
}   
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;since a lot of code can be necessary I invite to use my previous achievement : be able to make some include files in serverscripts files : I have it updated so this in the header of your serverscript file will make the trick : &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;eval(function (_files){
    var root = &quot;C:/inetpub/wwwroot/efficy/&quot; + ((typeof(Request) !== &quot;undefined&quot;)? Request.CustomBaseURL: &quot;../customs/Test/&quot;);
    var result = &quot;&quot;;
    for (var i=0; i&amp;lt;_files.length; i++) result += (StrLoadBinaryFile(root + _files[i])) + &quot;\r\n&quot;;
    return result;
}([
    &quot;serverscripts/NL_server_tools.js&quot;
    ,&quot;serverscripts/NL_server.js&quot;
    ,&quot;serverscripts/json2.js&quot;
]));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;in this example I chose to regroup all Efficy specific functions in NL&lt;em&gt;server.js&lt;br&gt;
and all the pure javascripts tools as the splice polyfill in NL&lt;/em&gt;server_tools.js&lt;br&gt;
libjson is the copy of the standard libjson library used sometimes in some scripts. (JSON.parse and stringify)&lt;/p&gt;

&lt;p&gt;Cheers. feel free to improve this code or ask for all the librairies if you need it &lt;br&gt;
please share your code afterward.&lt;/p&gt;
</description>
<category>WorkFlow / Serverscript</category>
<guid isPermaLink="true">https://overflow.efficy.io/?qa=2924/get-the-result-of-a-select-statement-to-an-array-of-object</guid>
<pubDate>Fri, 09 Feb 2018 14:36:11 +0000</pubDate>
</item>
<item>
<title>How to found the list of columns of a DataSet ?</title>
<link>https://overflow.efficy.io/?qa=1951/how-to-found-the-list-of-columns-of-a-dataset</link>
<description>&lt;p&gt;Hi to all,&lt;/p&gt;

&lt;p&gt;I want to write a &quot;generic&quot; function to read data via a SQL request...&lt;br&gt;
The problem is that I don't know the list of columns inside the Dataset result, while the query is build +/-  dynamically...&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; var mysql = &quot;select * from COMPANIES&quot;   // &amp;lt;- query unknow 
 var myDataSet = Database.ExecuteSystemSQLQuery(0, Database.OpenTemporaryContext, mysql, null, true, true, 36); //
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Is a way to obtain something like :&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var columns = myDataSet.Columns(); //   [ 'K_COMPANY', 'NAME',... ]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Regards&lt;br&gt;
Didier&lt;/p&gt;
</description>
<category>WorkFlow / Serverscript</category>
<guid isPermaLink="true">https://overflow.efficy.io/?qa=1951/how-to-found-the-list-of-columns-of-a-dataset</guid>
<pubDate>Fri, 21 Oct 2016 08:28:35 +0000</pubDate>
</item>
</channel>
</rss>