意图服务中的多个异步 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 Server 数据库
实体框架和经典 Ado.net 之间的单个事务或批量插入操作下的 SqlBulkCopy 多个表插入
通过 C# 使用 ado.net 将值插入 SQL Server 数据库