意图服务中的多个异步 Ado.net sql 插入

Posted

技术标签:

【中文标题】意图服务中的多个异步 Ado.net sql 插入【英文标题】:Multiple async Ado.net sql inserts in intent service 【发布时间】: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 我添加了代码以及一些调查结果。 【参考方案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() 方法中。

【讨论】:

以上是关于意图服务中的多个异步 Ado.net sql 插入的主要内容,如果未能解决你的问题,请参考以下文章

使用 ADO.NET 如何将数据列表插入 SQL?

使用 ADO.Net 数据集将数据插入 SQl Server 数据库

实体框架和经典 Ado.net 之间的单个事务或批量插入操作下的 SqlBulkCopy 多个表插入

通过 C# 使用 ado.net 将值插入 SQL Server 数据库

如何将自定义子查询传递给 ADO.NET 中的 SQL 命令?

SQL Server之 ADO增删查改 登录demo 带参数的sql语句 插入自动返回行号