C#异步并等待数据库循环

时间:2020-07-04 17:34:43

标签: c# asynchronous async-await backgroundworker

我面临一个小问题。我已经制作了一个功能,可以将客户从我的网站导入到我的数据库中以创建发票,等等。.当该功能启动时,它调用另一个功能以仅导入新客户。现在,我要等待最后一个功能,以防止我在家的软件可以搜索新导入的客户。这种客户导入非常简单,它仅选择未通过循环导入的客户。但是我也做了一些安全措施,以防万一出了问题。您知道,大多数错误都来自人为输入错误...但是使此功能异步以使其他功能在导入新客户时可以等待的最佳方法是什么?

public async Task<bool> ImportClients(bool onlyNewCustomers)
{
    System.Data.DataTable Table = new System.Data.DataTable();
    System.Data.DataTable CustomerTable = new System.Data.DataTable();
    System.Data.DataTable KlantTable = new System.Data.DataTable();

    int PrestaCustomerID = 0; //original customer id from the prestashop
    int CustomerID = 0; //Original customerID from software customer
    int CustomerIdInserted = 0; //id from the inserted customer id in the software
    int Wait = 0; //This var is used for the mysql to wait a few miliseconds between x updates

    string Sql = "";
    string Prefix = "";
    DateTime Bday;
    //Vars for logging
    int CustomersImported = 0;
    StringBuilder NewCustomerInfo = new StringBuilder();
    StringBuilder NewCustomerAddress = new StringBuilder();

    //Select everything whithin the customers table. After that we look if the customer is imported else we update the clients credentials.
    Sql =
        "SELECT c.id_customer, id_gender, c.firstname, c.lastname, c.email, c.birthday, c.newsletter, c.optin, c.website, " +
        "c.active, c.date_add, c.date_upd, c.imported FROM ps_customer c " +
        (onlyNewCustomers ? "WHERE imported = 0 " : "") + "ORDER BY c.id_customer DESC;";
    Table = Functions.SelectWebQuery(Sql);
    if (Table.Rows.Count > 0)
    {
        for (int i = 0; i < Table.Rows.Count; i++)
        {
            if (somethingGoesWrong)
            {
                return false;
            }
        }

        return await Task.WhenAll<bool>(true);
    }
}

我试图调用此功能的地方

public async static void OrderImport()
{
    Functions fns = new Functions();
    bool importCustomers = await fns.ImportClients(true);
}

我在Winforms中将.net 4.5与mysql数据库一起使用。

谢谢! 保罗

1 个答案:

答案 0 :(得分:1)

我的建议不是返回Task<bool>,而是返回新导入的客户。如果没有新客户,或者有小错误,则下次导入新客户时可能已解决,请返回一个空列表。对于需要立即采取措施的错误,请提出例外。

更多信息,我将提供一种额外的方法来吸引新客户:FetchNewCustomersFetchCustomers(true)更容易理解其作用。

public Task<ICollection<Customer> FetchNewCustomersAsync()
{
    return FetchCustomersAsync(true);
}
public Task<ICollection<Customer> FetchCustomersAsync(bool newOnly)
{
    ... // TODO: implement
}

显然,您有一个返回DataTable的方法Functions.SelectWebQuery(string)。此返回的DataTable需要转换为一系列Customer。

作为扩展方法。参见extension methods demystified

public static IEnumerable<Customer> ToCustomers(this DataTable table)
{
     // in this method you handle the problems if the table is not a table of Customers
    foreach(DataRow dataRow in table.AsEnumerable)
    {
         Customer customer = new Customer()
         {
              ... // fetch values from DataRow: dataRow.Field<string>("Name");
         }
         yield return customer;
    }
}

用法:

string sql = ...
IEnumerable<Customer> customers = Functions.SelectWebQuery(sql).ToCustomers()

或异步版本:

IEnumerable<Customer> customers = (await Functions.SelectWebQueryAsync(sql))
    .ToCustomers();

您需要选择一个sql,具体取决于您是要所有客户还是仅新客户:

public string sqlTextAllCustomers {get; }
public string sqlTextNewCustomers {get; }

现在我们准备实现FetchCustomersAsync:

public Task<ICollection<Customer> FetchCustomersAsync(bool newOnly)
{
    string sqlText = newOnly ? sqlTextNewCustomer : sqlTextAllCustomers;

    try
    {
         // in baby steps:
         DataTable fetchedData = await Functions.SelectWebQuery(sqlText);
         return fetchedData.ToCustomers();
    } 
    catch(Exception exc)
    {
        // TODO: detect if serious error or not
        if (isSeriousError)
            throw exc;
        else
        {
            // not a serious error: we'll process the new customers next time
            return Enumerable.Empty<Customer>();
        }
    } 
}