我有这个API删除并将不同的用户添加到数据库中。编写此API的方式如下:
/* Assuming 'users' is an array of users to delete (if users[x].toDelete == true),
or to add otherwise */
using (var db = new myContext())
{
using (var dbTransaction = db.Database.BeginTransaction())
{
try
{
/* Performing deletion of Users in DB */
SaveChanges();
/* Performing add of Users in DB */
foreach(user in users)
if (!user.toDelete) {
db.users.add(..);
db.SaveChanges();
}
dbTransaction.Commit();
}
catch (ValidationException ex)
{
dbTransaction.Rollback();
}
}
}
我使用事务的原因是我有一些应该在新数据上运行的验证。例如,我不能添加两个用户使用相同的电子邮件!
所有验证服务器端都使用Data-Annotations和MetaData类完成,因此我创建了属性唯一性,它与UserMetaData类的属性电子邮件相关联。
所以,问题在于,在Uniqueness Attribute中我需要再次检查数据库以搜索具有相同电子邮件的其他用户:
public class IsUnique : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
...
using (var db = new myContext()) {
/* Here I perform a select on the DB looking for records
with the same email, all using Reflection. */
if (recordFound > 0)
return new ValidationResult("email already exists");
return ValidationResult.Success;
}
}
}
所以,正如你所看到的,在验证中我使用new myContext()
,问题出在哪里:让我假装我有一个空数据库,并在同一个查询中添加两个用户使用相同的电子邮件。
正如您所看到的,我在添加每个用户后调用db.SaveChanges()
,因此我认为,当要添加的第二个用户已经过验证时,我的验证会知道添加了第一个用户并且第二个具有相同的电子邮件,因此将抛出验证异常并调用dbTransaction.Rollback()
。
问题是在验证器内部我调用了new myContext()
并且在那个上下文中我认为那些因为db.SaveChanges()
而没有的变化,我认为这是因为所有变更在交易中。
Sooo ..到目前为止我认为的解决方案有两个:
db.SaveChanges()
时都会运行一些内部事务。执行此操作,验证确实会看到更改,但问题是,如果在我调用outerTransaction.rollback()
的catch中,内部事务所做的更改不会回滚;