我正在使用实体框架从数据库中读取一些数据(读取成功),并且修改实体的效果很好,但是并不能将更改保存到数据库中。
该代码读取15条记录,但不会在循环内遍历它们。它遍历列表的第一个元素,并停在DbContext.SaveChanges()而不保存更改。
知道我的代码有什么问题吗?
public async Task LinkCardAsync(postcardContext DbContext)
{
HttpClient cons = new HttpClient();
cons.BaseAddress = new Uri("http://cbsswfint01:53303/");
cons.DefaultRequestHeaders.Accept.Clear();
cons.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
using (cons)
{
try
{
var cardsData = DbContext.MasterpassBulkLoad.Take(15).ToList();
foreach (var cardDetails in cardsData)
{
Console.WriteLine(cardDetails.Msisdn);
Console.WriteLine(cardDetails.Status == null);
HttpResponseMessage res = await cons.PostAsJsonAsync("api/Cardmanagement/CardLoad", cardDetails);
cardDetails.Status = (int)res.StatusCode;
Console.WriteLine("before save");
DbContext.SaveChanges();
Console.WriteLine("After Save");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
_logger.LogError(ex.InnerException.StackTrace);
}
}
}
public void Run()
{
using (var DbContext = new postcardContext())
{
_cardLinkService.LinkCardAsync(DbContext);
}
Console.ReadKey();
}
答案 0 :(得分:1)
首先,您的呼叫代码应在等待对卡链接服务的呼叫。
但是,我认为问题的症结在于DbContext不是线程安全的,因此您应该避免在与非上下文相关的等待异步操作之后访问上下文。 (PostAsJsonAsync)根据同步上下文,等待的代码可以在其他线程上恢复。
例如,在[#]表示线程ID的情况下,
[1] using (var DbContext = new postcardContext())
[1] {
[1] _cardLinkService.LinkCardAsync(DbContext);
->(进入方法)
...
[1] var cardsData = DbContext.MasterpassBulkLoad.Take(15).ToList();
[1] foreach (var cardDetails in cardsData)
[1] {
[1] Console.WriteLine(cardDetails.Msisdn);
[1] Console.WriteLine(cardDetails.Status == null);
[1] HttpResponseMessage res = await cons.PostAsJsonAsync("api/Cardmanagement/CardLoad", cardDetails);
[2] cardDetails.Status = (int)res.StatusCode;
[2] Console.WriteLine("before save");
[2] DbContext.SaveChanges();
..在第一个迭代中,下一个迭代将在线程#2上继续,然后在等待之后,在另一个线程上恢复。也许#1,也许#3。
要观察线程切换,您可以添加:
Console.WriteLine(cardDetails.Status == null);
Console.WriteLine(string.Format("Thread #{0} (before)", Thread.CurrentThread.ManagedThreadId));
HttpResponseMessage res = await cons.PostAsJsonAsync("api/Cardmanagement/CardLoad", cardDetails);
Console.WriteLine(string.Format("Thread #{0} (after)", Thread.CurrentThread.ManagedThreadId));
cardDetails.Status = (int)res.StatusCode;
首先,删除异步调用/签名,然后尝试使用简单的同步解决方案来验证数据是否按预期持久。从那里可以执行异步操作,但是我可以通过单个SaveChangesAsync
调用将数据加载,Web服务调用和数据更新/保存操作包装到单个可等待的方法中,而DbContext的范围仅限于该方法调用。 / p>
免责声明:如果要作为控制台应用程序运行,则完全不需要async / await。如果这是作为请求服务的一部分在Web服务器上处理的,则使用Async / await可以通过释放请求处理线程,同时后台线程通过HTTP通知和数据库更新搅动时,使服务器对请求的响应更快。考虑到选择记录进行处理的方式,该设计看起来不适合并行处理(乐趣与异步/等待不同)。并行运行最终可能会相互获取一次运行中相同的15条记录中的某些记录。根据我在代码中看到的内容,我会说异步没有任何好处,如果有的话,它将使整体运行速度变慢。但是要概述异步方法,它看起来像这样:
using (var cons = new HttpClient())
{
cons.BaseAddress = new Uri("http://cbsswfint01:53303/");
cons.DefaultRequestHeaders.Accept.Clear();
cons.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
try
{
using(var context = new DbContext())
{
var cardsData = await context.MasterpassBulkLoad.Take(15).ToListAsync();
foreach (var cardDetails in cardsData)
{
Console.WriteLine(cardDetails.Msisdn);
Console.WriteLine(cardDetails.Status == null);
HttpResponseMessage res = cons.PostAsJson("api/Cardmanagement/CardLoad", cardDetails);
cardDetails.Status = (int)res.StatusCode;
}
Console.WriteLine("before save");
await context.SaveChangesAsync();
Console.WriteLine("After Save");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
_logger.LogError(ex.InnerException.StackTrace);
}
}
上面的代码将以15的批次保存结果,因此如果任何1行由于某种原因失败,则将不会保存任何内容。您还应该检查“ Take 15”行为,因为它看起来总是会拾取相同的15行。使用Take
时,应始终包含OrderBy
以保持一致的行为。我假设它指向一个正在检查状态的视图?