private void BillingEngine_BeforeSave(object sender, MercatorUi.Engine.Gescom.BillingEngine.BeforeSaveEventArgs e)
{
    MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
    DataTable dtArticles = new DataTable();
    dtArticles.Columns.Add("s_id", typeof(string));
    foreach(DataRow dr in billingEngine.LIGNES.Select("id_article<>''"))
        dtArticles.Rows.Add(new object[1] { dr["id_article"] });
    using (MercatorSqlConnection conn = new MercatorSqlConnection(MercatorUi.Globals.RepData, true))
    {
        if (conn.Connection == null)
        {
            e.CancelSave = true;  // connexion refusée par le serveur SQL -> on arrête la sauvegarde
            return;
        }
        if (!Api.BulkDataTable(dtArticles, "#art_tmp", conn.Connection, null, "STOCK"))
        {
            e.CancelSave = true; // erreur lors du bulk de la DataTable -> on arrête la sauvegarde
            return;
        }

        using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("", conn.Connection))
        {
            cmd.CommandText = "select s_id,s_xxx,s_yyy from STOCK inner join #art_tmp on (stock.s_id=#art_tmp.s_id) \r\n"
                            + "drop table #art_tmp";
            DataSet ds = Api.Zselect(conn.Connection, cmd);
            if (ds == null)
            {
                e.CancelSave = true;  // la requête ci-dessus a renvoyé une erreur -> on arrête la sauvegarde
                return;
            }
            Api.TrimEndDataTable(ds.Tables[0]);

            // fin du traitement préliminaire avant le code en boucle


            // début du traitement dans la boucle des lignes

            foreach (DataRow dr in billingEngine.LIGNES.Select("id_article<>''"))
            {
                DataRow[] foundRows = ds.Tables[0].Select(string.Format("s_id='{0}'", Api.UnquoteSql(dr["id_article")))):
                if (foundRows.Length > 0) // sera toujours le cas, car tous les articles existent
                {
                    dr["xxx"] = foundRows[0]["s_xxx"];
                    dr["yyy"] = foundRows[0]["s_yyy"];
                }
            }
        }
    }
}