在sproc之后和事务内部更新实体

时间:2015-05-04 21:01:21

标签: c# entity-framework transactions

传入的类比。

class Herd
{
    public List<Animal> Animals { get; set; }
}

class Animal
{
    //at least for today, animals have opinions
    public List<Opinion> Opinions { get; set; }
}

class Opinion { }

我们希望从美国东部到美国西部一次性移动不同的畜群。我们为每一个移动的牧群创建一个交易。在该事务中,我们调用了一些存储过程。其中一个为动物添加了一些默认意见。稍后在同一事务的C#代码中,我们手动向动物添加意见,但它们依赖于默认意见。

using (var trans = _context.Database.BeginTransaction())
{
    try
    {
        _context.Herds.Add(herd);
        _context.SaveChanges();

        Proc1Wrapper(herd);
        Proc2Wrapper(herd);
        Proc3Wrapper(herd);
        InsertDefaultOpinionsProc(herd);

        //this does not load the default opinions:
        herd = _context.Herds.Where(o => o.HerdID == herd.ID).First();

        //this does not either:
        herd = _context.Herds.Find(herd.ID);

        //this doesn't either:
        _context.Entry(herd).Reload();

        //this **does** load the default opinions
        foreach (var animal in herd.Animals)
            _context.Entry(animal).Collection("Opinions").Load();

        //dependent on default opinions
        AddOpinionsManually(herd);

        _context.SaveChanges();
        trans.Commit();
    }
    catch 
    {
        trans.Rollback();
        throw;  
    }
}

随着一堆存储过程被调用,我想将整个群体视为脏并重新加载群体对象,但我找不到办法来做到这一点。我错过了什么?

1 个答案:

答案 0 :(得分:0)

如果使用SQL Profiler跟踪此代码,您将看到在提交trans之前默认意见不适用于新的群组(我假设您使用的是默认SQL Server隔离级别{ {3}})。您可以使用嵌套事务来解决此问题。

//this will start a new transaction
using (var trans = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    try
    {
        _context.Herds.Add(herd);
        _context.SaveChanges();

        //this will use the "ambient" transaction but can commit separately
        using (wrapperTransaction = new TransactionScope(TransactionScopeOption.Required))
        {
            Proc1Wrapper(herd);
            Proc2Wrapper(herd);
            Proc3Wrapper(herd);
            InsertDefaultOpinionsProc(herd); 
            wrapperTransaction.Commit() //now your default opinions are inserted into the db
        }

        //this should return the herd now fully opinionated :)
        herd = _context.Herds.First(o => o.HerdID == herd.ID);

        AddOpinionsManually(herd);

        _context.SaveChanges();
        trans.Commit();
    }
    catch 
    {
        trans.Rollback();
        throw;  
    }
}