【问题标题】:Multiple async Ado.net sql inserts in intent service意图服务中的多个异步 Ado.net sql 插入
【发布时间】:2017-06-21 14:30:48
【问题描述】:

我有一个执行以下操作的意图服务:

  • 从意图中提取字符串参数,

  • 使用参数组成http查询,

  • 使用异步任务和 System.Net.Http 执行,

  • 解析接收到的 json 并将一些字段值放入字符串 sqlQuery 中,该字符串应该将数据插入到 sqlite db,

  • 使用 Ado.net 执行 sqlQuery(使用打开连接然后关闭连接的方法)。

请注意,调用服务的意图可能有多个,具有不同的 PutExtra 值。因此,活动告诉服务:“加载 City1 的信息”、“加载 City2 的信息”……等等。

UPD。意图服务代码:

public WeatherService() : base("WeatherService")
    {
    }

    public string sqlQuery;

    protected override async void OnHandleIntent(Android.Content.Intent intent)
    {

        // Get extras
        string wsMode = intent.GetStringExtra("mode");
        string wsLocation = intent.GetStringExtra("location");
        string wsProvider = intent.GetStringExtra("provider");
        string wsUpdId = intent.GetStringExtra("upd_id");
        //string debugMsg = "INTENT_SERVICE_OUTPUT: Mode " + wsMode + ", location " + wsLocation + " , provider " + wsProvider;
        //Console.WriteLine(debugMsg);

        // Generate http string
        string httpQuery = "";
        switch (wsProvider)
        {
            case "openweathermap":
                httpQuery = "http://api.openweathermap.org/data/2.5/weather?&appid=1&units=metric&lang=ru"; //fake key here
                if (wsMode == "code") { httpQuery = httpQuery + "&id=" + wsLocation; }
                break;
            default:
                httpQuery = "";
                break;
        }

        // Get weather from the provider
        dynamic results = await DataService.getDataFromService(httpQuery);
        if (results["weather"] != null)
        {

            // Compose insert queries
            if (sqlQuery == null) { sqlQuery = ""; Console.WriteLine("SQL QUERY FROM NULL TO EMPTY STRING"); }
            sqlQuery = sqlQuery +
                "INSERT INTO [Weather] ([IND_ID], [UPD_ID], [CITY_ID], [VALUE], [SHOW], [DATE], [TIME]) " +
                    "SELECT [IND_ID],'" + wsUpdId + "','" + (string)results["id"] + "','" + (string)results["weather"][0]["description"] +
                    "',1,NULL,NULL FROM [Indicators] WHERE [CAPTION] = 'currentConditions';" +
                "INSERT INTO [Weather] ([IND_ID], [UPD_ID], [CITY_ID], [VALUE], [SHOW], [DATE], [TIME]) " +
                    "SELECT [IND_ID],'" + wsUpdId + "','" + (string)results["id"] + "','" + (string)results["main"]["temp"] +
                    "',1,NULL,NULL FROM [Indicators] WHERE [CAPTION] = 'currentTemperature';";
            Console.WriteLine(sqlQuery);
        }


    }

    public override void OnDestroy()
    {

        // Insert data into databse
        if (sqlQuery != null) { Sql.ExecQueryScalarOrNonQuery(sqlQuery, 0); Console.WriteLine("SQL_QUERY: INSERTED"); } else { Console.WriteLine("SQL_QUERY: EMPTY!!!"); }

        // Update current view
        // TODO

        // End Service
        base.OnDestroy();

所以,如您所见,我尝试声明一个名为 sqlQuery 的字符串,并尝试在其中插入一些数据。但问题是:要正确地问http异步任务,我不得不让所有的OnHandleIntent方法

受保护的覆盖异步 void OnHandleIntent()

所以,当 sqlQuery 仍然为空时,启动 OnHandleIntent 并立即启动 OnDestroy() !!!而就在几秒钟前,OnHandleIntent-s(在我的例子中是两个)完成了。

那么,如何进行以下操作:在 OnHandleIntent 中,我们获得额外内容,生成并启动 http 查询(使用异步任务而不是???),然后我们为 db in 生成并保存插入(为了简单起见,让我们在字符串 sqlQuery ;) )。然后,当所有 OnHandleIntent 都准备好时,我们执行最终的 sqlQuery(一次)并通过调用 base.OnDestroy() 结束服务。提前问好。

【问题讨论】:

  • 发布实际代码。从描述中唯一清楚的是,有一个错误。异步执行与问题有什么关系 - 除非您尝试使用相同的连接来运行多个命令(不要)?
  • 如果要快速插入大量数据,使用SqlBulkCopy。不要试图“并行化”插入,你只会让事情变得更糟很多。在一条语句中发送 100 个插入比尝试并行执行 100 个插入并最终相互锁定要快 100 倍。如果您使用具有 100 个值的 INSERT VALUES 语句,您可以走得更快。不过,没有什么比 SqlBulkCopy 更好的了 - 它使用与 bcp 和 BULK INSERT 相同的批量导入机制。
  • SqlBulkCopy 使用 minimal 日志记录 - 它不记录每个语句,它只记录修改后的数据页。
  • @PanagiotisKanavos 谢谢!我将研究批量插入或至少执行一个插入值构造
  • @PanagiotisKanavos 我添加了代码以及一些调查结果。

标签: c# xamarin xamarin.android async-await android-service


【解决方案1】:

我决定将方法声明更改为

受保护的覆盖无效

并重写 DataService 类以使异步 -> 同步如下:

public class DataService
{
    public static object ReceivedData(string queryString)
    {

        // Exec the query
        dynamic data = null;
        using (HttpClient client = new HttpClient())
        {
            var response = client.GetAsync(queryString).Result;

            // If result is not null, deserialize json
            if (response != null)
            {
                string json = response.Content.ReadAsStringAsync().Result;
                data = JsonConvert.DeserializeObject(json);
            }

        }

        // Return json result
        return data;

    }
}

在我的情况下,所有工作(同步)在意图服务线程中,然后成功插入到本地sqlite db(在意图服务的 OnDestroy() 方法中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 2017-06-03
    • 1970-01-01
    • 2012-05-20
    • 2022-08-22
    • 2021-08-12
    • 2013-12-19
    相关资源
    最近更新 更多