提问者:小点点

逐行发送,不重复


我有下表

正如您所看到的,有一个名为bool类型Integration的列,所有这个表都通过一个存储过程显示在DataGridView中,该存储过程是

CREATE PROCEDURE [dbo].[SP_Payments]
AS 
SELECT 'CE-'+CardCode AS CardCode,DocType,Series,DocDate,dbo.udf_GetNumeric(DocNum) AS DocNum,
DocEntry,TrsfrAcct,TrsfrDate,TrsfrSum, Integration,Comments,SumApplied
FROM  PaymentsReceived WHERE Integration = 0

这个SP说只向我显示那些为0的值,这是false的值,我对那些为false的值所做的是通过web服务发送它们,我有一个方法,它遍历每一行,并在每次发送时发送它,将它设置为true,然后它从DataGridView中消失,这个方法在一个计时器中,每5秒触发一次,在这个方法中有一个条件,如果集成为==false,让它发送,这就是方法。

private async void Envio_Timer_Tick(object sender, EventArgs e)
        {
            try
            {
                ProxyBL proxy = new ProxyBL();
                foreach (DataGridViewRow Datos in dataGridView1.Rows)
                {
                    PagosRecibidos pagos = new PagosRecibidos
                    {
                        CardCode = Convert.ToString(Datos.Cells[0].Value),
                        DocType = Convert.ToString(Datos.Cells[1].Value),
                        Series = Convert.ToInt32(Datos.Cells[2].Value),
                        DocDate = Convert.ToDateTime(Datos.Cells[3].Value),
                        DocEntry = Convert.ToInt32(Datos.Cells[5].Value),
                        TrsfrAcct = Convert.ToString(Datos.Cells[6].Value),
                        TrsfrDate = Convert.ToDateTime(Datos.Cells[7].Value),
                        TrsfrSum = Convert.ToDecimal(Datos.Cells[8].Value),
                        Integration = Convert.ToBoolean(Datos.Cells[9].Value),
                        Comments = Convert.ToString(Datos.Cells[10].Value),
                        SumApplied = Convert.ToDecimal(Datos.Cells[11].Value)
                    };
                    Inte = pagos.Integration;
                    if (Inte == false)
                    {
                        var EnvioDatos = await proxy.EnviarPago(pagos);
                    }
                    ListarEmple();
                    ListarLog();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

这就是SendPayment的方法

这个方法从服务获得响应,如果操作成功或失败,它会将其插入日志中

Consultas c = new Consultas();

        public async Task<string> EnviarPago(PagosRecibidos detalle)
        {
            try
            {
                ProxyXML xmlProxy = new ProxyXML();
                string respuesta = await xmlProxy.EnviarSAP(detalle);
                c.InsertarLog(1, DateTime.Now, respuesta, xmlProxy.XmlSerializado);
                return respuesta;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

在此方法之后,输入装运、EnviaSAP

这是我捕获答案的地方,如果操作成功,那么给我集成列为“1 true”。

readonly Consultas c = new Consultas();  
        public string XmlSerializado = null;

    public async Task<string> EnviarSAP(PagosRecibidos detalle)
    {
        try
        {
            using (WSSincronizacionClient clienteSAP = new WSSincronizacionClient())
            {
                XmlSerializado = this.SerializarXml(detalle);
                var respuesta = await clienteSAP.EnviarDatosSAPAsync(XmlSerializado);
                if (respuesta.Contains("true|Operación Exitosa|"))
                {
                    c.EditarIntegration(true, Convert.ToInt32(detalle.DocEntry));
                }
                return respuesta;
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

每件事都正常工作,但当发送它时,有时它发送它两次或重复,即在SAP中它到达两次,我如何做这个验证,那个是假的只进入我一次,它没有发送它两次,我应该在哪个部分做这个验证

我也不知道为什么如果你已经确认我只发了假的,你还发了两次。


共1个答案

匿名用户

我唯一能想到的是,处理单个行的时间超过了计时器间隔,因此您可能在两个处理程序调用中并行地迭代同一个项,因为没有足够的时间让另一个处理程序完成它的处理。

也许您可以在获取该行时标记该行,并保存更改,以便该标记可以作为其他计时器刻度处理程序调用忽略该行的鉴别器:

foreach (DataGridViewRow Datos in dataGridView1.Rows)
{
    var alreadyProcessingRow = Convert.ToBoolean(Datos.Cells[{ProcessingFlagColumnIndex}].Value);
    if(alreadyProcessingRow)
        continue; //skip the row, don't reprocess it

    Datos.Cells[{ProcessingFlagColumnIndex}] = true; //Mark the row as processing

    PagosRecibidos pagos = new PagosRecibidos
    {
        CardCode = Convert.ToString(Datos.Cells[0].Value),
        DocType = Convert.ToString(Datos.Cells[1].Value),
        Series = Convert.ToInt32(Datos.Cells[2].Value),
        DocDate = Convert.ToDateTime(Datos.Cells[3].Value),
        DocEntry = Convert.ToInt32(Datos.Cells[5].Value),
        TrsfrAcct = Convert.ToString(Datos.Cells[6].Value),
        TrsfrDate = Convert.ToDateTime(Datos.Cells[7].Value),
        TrsfrSum = Convert.ToDecimal(Datos.Cells[8].Value),
        Integration = Convert.ToBoolean(Datos.Cells[9].Value),
        Comments = Convert.ToString(Datos.Cells[10].Value),
        SumApplied = Convert.ToDecimal(Datos.Cells[11].Value)
    };
    Inte = pagos.Integration;
    if (Inte == false)
    {
        var EnvioDatos = await proxy.EnviarPago(pagos);
    }
    Datos.Cells[{ProcessingFlagColumnIndex}] = false; //reset the flag (not that important if you just don't care after processing)
    ListarEmple();
    ListarLog();
}

我不确定是否可以使用datagridview对象来实现这一点,但如果不能,可以使用ConcurrentDictionary,并将当前正在处理的行(或行ID)存储在那里,以便检查和避免重复处理。