【发布时间】:2014-06-09 06:01:54
【问题描述】:
在我调用 SaveChanges() 后,数据库返回新记录的 ID。每次我将一个新对象传递给我的 Add 方法时,ID 都会增加,所以我知道数据库(Azure)在循环中。但实际上没有任何东西被插入到数据库中,因为有一个回滚。除了做 .Find(newId) 和测试 null,这意味着另一次访问数据库之外,还有什么办法可以捕捉到这个?
发生这种情况是因为我无意中创建了一个需要插入相关表的关系。让我烦恼的是交易默默地失败了。如果我一直在使用 ADO.NET 和参数化存储过程,它会抛出异常并返回一些有用的东西。
我是 EF / Code First 的新手,并且正在从事一个新建项目,因此可以先使用代码构建数据库。到目前为止,这是一次冒险。
更新:根据 Aron 的要求提供代码。此外,更多的背景。我使用的是 NLogMvc,它有自己的上下文将消息写入数据库。 Aron 提到的分布式事务可能存在问题。无论如何,我都对解决方案进行了重组,删除了 NLogMvc,并转移到了 Ninject.Extensions.Loggings.nlog2
我知道数据库上发生的事情是我未能清理一些插入相关表所需的旧代码。 SQL Server 在回滚事务时会抛出错误。
问题的最终更新:我对可能导致问题的所有假设都是错误的。结果我无意中在存储库构造函数中创建了一个 TransactionScope 实例。有关详细信息,请参阅我对我自己的问题的回答(如下)。
代码:
public int AddUpdateSlideshow(SlideshowDto slideshow)
{
if (!_user.IsInRole("Admin")) return -1;
bool isNewShow = false;
var now = DateTime.Now;
try
{
using (var context = new ApplicationDbContext())
{
context.Database.Log = s => _logger.Info(s);
int slideshowId;
if (slideshow.SlideshowId == 0)
{
isNewShow = true;
var newSlideshow = new Slideshow
{
Name = slideshow.Name,
Description = slideshow.Description,
DateAdded = now,
AddedBy = _userName,
DateLastUpdated = now,
UpdatedBy = _userName,
IsActive = slideshow.IsActive
};
context.Slideshows.Add(newSlideshow);
context.SaveChanges();
slideshowId = newSlideshow.SlideshowId;
}
else
{
Slideshow dbUpdate =
context.Slideshows.Find(
slideshow.SlideshowId);
if (dbUpdate != null)
{
slideshowId = slideshow.SlideshowId;
dbUpdate.Name = slideshow.Name;
dbUpdate.Description = slideshow.Description;
dbUpdate.IsActive = slideshow.IsActive;
dbUpdate.DateLastUpdated = now;
dbUpdate.UpdatedBy = _userName;
context.SaveChanges();
// Number of objects written to the database.
// Zero means the update failed.
int result = context.SaveChanges();
slideshowId = result == 0 ? result : slideshow.SlideshowId;
}
else
{
var errorMessage = string.Format(
"The {0} method in {1} threw an ArgumentNullException exception. The user was {2}.",
MethodBase.GetCurrentMethod().Name, _className, _userName);
_logger.Error(errorMessage);
throw new ArgumentNullException("slideshow");
}
}
// The database will return new id value BUT
// if for some reason the transaction fails the
// changes will be rolled back and we won't have the
// new record. So we need to confirm that we do in
// fact have one.
if (isNewShow)
{
var newShow = context.Slideshows.Find(slideshowId);
if (newShow == null)
{
slideshowId = 0;
}
}
return slideshowId;
}
}
catch (Exception ex)
{
var errorMessage = string.Format("The {0} method in {1} threw an exception. The user was {2}.",
MethodBase.GetCurrentMethod().Name, _className, _userName);
_logger.Error(errorMessage, ex);
return -1;
}
}
【问题讨论】:
-
请输入代码。听起来您正在使用一个事务,它自动升级为分布式事务,但您从未提交过。 sscce.org
-
无法从我当前的位置访问我的代码,但今晚会添加它。但是,当我知道要访问多个表时,我使用了事务,但在这种情况下没有这样做;我认为 EF 在幕后为我做到了这一点。
-
不,它没有。 EF 的设计很合理,您认为如果不是这样,它会像现在这样受欢迎吗?答案就在您的源代码中。
-
引用这个 StackOverflow 答案(272 次赞成)“大多数情况下,使用实体框架 SaveChanges() 就足够了。这会创建一个事务,或加入任何环境事务,并完成所有必要的工作那笔交易。” stackoverflow.com/questions/815586/…
-
最重要的是它关闭了交易,如果它未能关闭交易,它会在异常情况下通知您。又名理智。
标签: .net entity-framework dbcontext