C# 批量更新行值ASP.NET Core C控制台应用程序
我有一个控制台应用程序,可以从instagram url获取json数据,如下所示: 因此,我需要查询所有具有非空instagram用户名的行,然后每行通过公共api进行IG查找,以获取IG帐户id并更新相应的db行 我有两段sql代码,它从表中进行全选,如果InstagramIds为空,则输出它们,另一个查询是根据instagram用户名更新instagram ID 如何对数据库中的每个InstagramMuserName进行批量搜索和更新,并将所有相应的instagram ID添加到数据库中C# 批量更新行值ASP.NET Core C控制台应用程序,c#,sql-server,asp.net-core,C#,Sql Server,Asp.net Core,我有一个控制台应用程序,可以从instagram url获取json数据,如下所示: 因此,我需要查询所有具有非空instagram用户名的行,然后每行通过公共api进行IG查找,以获取IG帐户id并更新相应的db行 我有两段sql代码,它从表中进行全选,如果InstagramIds为空,则输出它们,另一个查询是根据instagram用户名更新instagram ID 如何对数据库中的每个InstagramMuserName进行批量搜索和更新,并将所有相应的instagram ID添加到数据库中
public static async Task<InstagramUser> ScrapeInstagram(string url)
{
using (var client = new HttpClient())
{
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
// create html document
var htmlBody = await response.Content.ReadAsStringAsync();
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(htmlBody);
// select script tags
var scripts = htmlDocument.DocumentNode.SelectNodes("/html/body/script");
// preprocess result
var uselessString = "window._sharedData = ";
var scriptInnerText = scripts[0].InnerText
.Substring(uselessString.Length)
.Replace(";", "");
// serialize objects and fetch the user data
dynamic jsonStuff = JObject.Parse(scriptInnerText);
dynamic userProfile = jsonStuff["entry_data"]["ProfilePage"][0]["graphql"]["user"];
//Update database query
string connectionString = @"Server=MyProject-dev-db.cothtpanmcn7.ap-southeast-2.rds.amazonaws.com;Database=UserApp;User Id=testadmin;Password=test123;MultipleActiveResultSets=true;Trusted_Connection=False;";
using (SqlConnection con = new SqlConnection(connectionString))
{
//select all users with null value
SqlCommand select = new SqlCommand("Select * from ApplicationUser where InstagramId is null");
//Updates InstagramID based from user input of instagramUsername
SqlCommand cmd = new SqlCommand("Update ApplicationUser Set InstagramId = '" + userProfile.id + "'" + "where Instagram = '" + userProfile.username + "'", con);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
// create an InstagramUser
var instagramUser = new InstagramUser
{
FullName = userProfile.full_name,
FollowerCount = userProfile.edge_followed_by.count,
FollowingCount = userProfile.edge_follow.count,
Id = userProfile.id,
url = url
};
return instagramUser;
}
else
{
throw new Exception($"Something wrong happened {response.StatusCode} - {response.ReasonPhrase} - {response.RequestMessage}");
}
}
}
你可以这样做 获取所有没有InstagramId的用户 循环遍历用户,并调用API 将数据从API映射到ApplicationUser 在SQL Server中创建临时表 在我的示例中,使用大容量复制在临时表中插入数据 使用临时表与ApplicationUser连接以更新大量行。 有点伪代码:
var applicationUsers = await GetAllApplicationUsersWithoutInstagramId(); // Get the records from the database
foreach(var user in applicationUsers)
{
var instagramInfo = await GetInstagramInfo(user ); // Get the data from the API
u.InstagramId = instagramInfo.Id;
// Map other properties
});
using (SqlConnection con = new SqlConnection(connectionString))
{
await con.OpenAsync();
var transaction = con.BeginTransaction();
// Create a temp table
var cmd = new SqlCommand("CREATE #NewData(InstagramUsername NVARCHAR(255) NOT NULL PRIMARY KEY, InstagramId BIGINT NOT NULL /*Other columns*/)", con, transaction);
await cmd.ExecuteNonQueryAsycn();
// Create a data table to use with the SqlBulkCopy
var table = new DataTable();
foreach (var applicationUser in applicationUsers)
{
var row = table.NewRow();
row["InstagramUsername"] = applicationUser.Instagram;
row["InstagramId "] = applicationUser.InstagramId;
/*Other columns*/
table.Rows.Add(row);
}
// Bulk insert the new data into the temp table
using var bulkCopy = new SqlBulkCopy(con, SqlBulkCopyOptions.Default, transaction)
{
DestinationTableName = "#NewData",
BulkCopyTimeout = 3600 // 1 hour
};
await bulkCopy.WriteToServerAsync(table);
// Perform the update
cmd = new SqlCommand(@"
UPDATE au
SET au.InstagramId = nd.InstagramId
/*Other columns*/
FROM ApplicationUser au
INNER JOIN #NewData nd on au.Instagram = nd.InstagramUsername
", con,transaction);
await cmd.ExecuteNonQueryAsync();
await transaction.CommitAsync();
}
没有大容量搜索和大容量更新,唯一的大容量操作是大容量插入。因此,我每次都必须进行单独的搜索才能更新表中的每一行?您可以同时更新多行,但不是在批量操作中。我知道如何获取所有为空的Instagramid,但我不知道如何循环并同时执行搜索以更新所有Instagramid。如果从SQL角度执行此操作,您可能不想循环。您将使用一个更新和一个新值连接到您的数据。在psuedo术语中:UPDATE I SET instagramID=ND.NewID FROM dbo.Instagram I JOIN NewData ND ON{Some JOIN子句};它如何知道哪个instagram用户名映射到哪个Id?您可以通过使用表的主键或instagram列的用户来做到这一点,请参阅updated answer.Parallel.ForEach用于数据并行,因此在任何情况下它都是完全无用的。并行运行8个SqlBulkCopy操作很容易导致1/8的性能,因为它们彼此冲突,试图在网络上使用相同的带宽,在服务器上使用相同的磁盘IO。最后,所有连接都会尝试更新同一个目标,彼此阻塞。有没有一种方法可以做到这一点而不创建新表?这个控制台应用程序只会使用几次,所以我不想为此更改数据库reason@PanagiotisKanavosParalle.ForEach并没有在SQL Server上进行任何数据访问,它只是在那里处理对外部api的调用。