您好,当我将ASP.NET MVC与EF结合使用并从其他网站(也使用Entity Framework)调用Web API时,发现了问题 问题是
我想确保MVC SaveChanges()
和Web API SaveChanges()
两者都成功。
这是我梦dream以求的伪代码
public ActionResult Operation()
{
Code Insert Update Delete....
bool testMvcSaveSuccess = db.TempSaveChanges(); //it does not have this command.
if(testMvcSaveSuccess == true)
{
bool isApiSuccess = CallApi(); //insert data to Other Web App
if(isApiSuccess == true)
{
db.SaveChanges(); //Real Save
}
}
}
根据上述代码,如果没有db.TempSaveChanges()
,则Web API可能会成功,但是MVC SaveChanges()
可能会失败。
答案 0 :(得分:2)
因此没有TempSaveChanges
之类的东西,因为还有更好的东西: Transactions 。
交易是一个IDisposable(可以在using块中使用),并且具有诸如 Commit 和 Rollback 的方法。
小例子:
private void TestTransaction()
{
var context = new MyContext(connectionString);
using (var transaction = context.Database.BeginTransaction())
{
// do CRUD stuff here
// here is your 'TempSaveChanges' execution
int changesCount = context.SaveChanges();
if (changesCount > 0)
// changes were made
{
// this will do the real db changes
transaction.Commit();
}
else
{
// no changes detected -> so do nothing
// could use 'transaction.Rollback();' since there are no changes, this should not be necessary
// using block will dispose transaction and with it all changes as well
}
}
}
我已从我的GitHub Exercise.EntityFramework存储库中提取了此示例。随意加星/克隆/叉...
答案 1 :(得分:0)
是的。
您需要在上下文类中重载.Savechanges
,在该类中将首先调用它,然后在之后调用常规。
或者在上下文类中创建您自己的TempSaveChanges()
,然后从中成功调用SaveChanges
。
答案 2 :(得分:0)
您所指的是 atomicity (原子性):您希望多项操作全部成功或全部都不成功。在数据库的上下文中,您可以通过交易获得此信息(如果数据库支持)。但是,就您而言,您需要一个跨越两个不相交系统的事务。通用的(某些特殊情况下具有更简单的解决方案)这种事务的可靠实现将对两个系统有一定要求,并且还需要额外的持久性。
基本上,您需要能够在序列中的任意时刻从突然停止中正常恢复。您正在使用的每个数据库很可能都符合 ACID ,因此您可以依靠每个数据库事务来满足原子性要求(它们成功或失败)。因此,您只需要担心两个数据库事务的顺序。您对这两个系统的要求是确定后验是否已执行某些操作的一种方法。
示例流程:
恢复:
现在,正如您所看到的,它很快变得复杂起来,特别是如果“确定是否进行了更改”不是一件容易的事。常见的解决方案是使用该唯一事务ID作为确定需要注意哪些数据的方式。但是在这一点上,它变得非常特定于应用程序,并且完全取决于特定的操作。对于某些应用程序,您只需在恢复步骤中重新运行整个操作(因为您已将整个请求数据存储在事务中)。某些特殊情况不需要持久化事务,因为还有其他方法可以实现相同的目的,等等。
答案 3 :(得分:0)
好的,让我们澄清一下。
您有一个MVC应用 A1 ,其数据库为 D1 您便有了一个API,我们将其称为 A2 和它自己的数据库 D2 。
您想要 A1 中的一些代码,该代码会在 D1 中进行临时保存,然后触发对 A2 的调用,如果响应成功然后将 D1 中的温度数据保存在正确的位置。
根据您的伪代码,建议您创建第二个表,将“临时”数据保存在 D1 中。因此您的数据库有一个额外的表,流程如下:
首先将 A1 数据保存在该表中,然后调用 A2 ,数据将保存在 D2 , A1 < / strong>收到确认并调用将数据从第二个表移至应有的位置的方法。
要考虑的场景:
将温度数据保存在 D1 中有效,但对 A2 的调用失败。现在,您可以使用批处理作业清除孤立数据,或仅调用 A2 失败时调用将其删除的数据。
对 A2 的调用成功,对 D1 的调用失败,所以现在您在 D1 中拥有临时数据,但该数据已失败移动到右边的桌子。您可以在第二行表的每一行添加一个标志,这表明对 A2 的第二次调用已成功完成,因此该数据需要尽可能地移到正确的位置。您可以在此处有一个定期运行的服务,如果它找到标记设置为true的任何数据,则会将数据移到正确的位置。
还有其他方法可以处理这种情况。您可以使用队列系统进行管理。每一行数据都变成一条消息,您为其分配一个唯一的ID,即GUID,它基本上是一个CorrelationID,并且在两个系统中都是相同的。即使一个系统出现故障,恢复运行时,数据也将被保存,并且一切都很好,而且由于具有通用ID,您始终可以正确地将其链接起来。