如何创建LINQ to SQL事务?


68

我有一段涉及多个插入的代码,但是需要在完成向其他表中的插入之前执行Submitchanges方法,以便我可以获取一个ID。我一直在互联网上搜索,找不到如何在linq to sql中创建事务。我已在要进行交易的代码中添加了注释。

    var created = false;
    try
    {
        var newCharacter = new Character();
        newCharacter.characterName = chracterName;
        newCharacter.characterLevel = 1;
        newCharacter.characterExperience = 0;
        newCharacter.userUsername = userUsername;
        newCharacter.characterClassID = ccslst[0].characterClassID;
        //Open transaction


            ydc.Characters.InsertOnSubmit(newCharacter);
            ydc.SubmitChanges();

            foreach (var ccs in ccslst)
            {
                var cs = new CharacterStat();
                cs.statId = ccs.statID;                        
                cs.statValue = ccs.statValue;
                cs.characterID = newCharacter.characterID;
                ydc.CharacterStats.InsertOnSubmit(cs);
            }                    


            var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID);
            foreach (var ccb in ccblst)
            {
                var charBody = new CharacterBody();
                charBody.bodyId = ccb.bodyId;
                charBody.bodyPartId = ccb.bodyPartId;
                charBody.characterID = newCharacter.characterID;
                ydc.CharacterBodies.InsertOnSubmit(charBody);
            }
            ydc.SubmitChanges();      
            created = true;
        //Commit transaction
        }
        catch (Exception ex)
        {
            created = false;
            //transaction Rollback;                    
        }
        return created;

编辑:忘记提及ydc是我的datacontext

Answers:


68

把整个包裹在一个盒子里TransactionScopetransaction.Complete()在您要提交的位置致电。如果代码未Complete()调用而退出该块,则事务将回滚。但是,在查看@s_ruchit的答案并重新检查您的代码之后,您可能可以重写此代码而不需要TransactionScope。第一个示例TransactionScope按原样使用和代码。第二个示例进行了一些小的更改,但实现了相同的目的。

您需要使用 TransactionScope当您从数据库中读取值并使用它在要添加的对象上设置新值时,。在这种情况下,LINQ事务将不覆盖第一次读取的内容,而仅覆盖后来提交的新值。由于您使用读取中的值来计算写入的新值,因此需要将读取包装在同一事务中,以确保其他读取器不会计算相同的值并避免您的更改。在您的情况下,您仅在执行写操作,因此标准的LINQ事务应该起作用。

范例1:

var created = false;

using (var transaction = new TransactionScope())
{
    try
    {
        var newCharacter = new Character();
        newCharacter.characterName = chracterName;
        newCharacter.characterLevel = 1;
        newCharacter.characterExperience = 0;
        newCharacter.userUsername = userUsername;
        newCharacter.characterClassID = ccslst[0].characterClassID;

        ydc.Characters.InsertOnSubmit(newCharacter);
        ydc.SubmitChanges();

        foreach (var ccs in ccslst)
        {
            var cs = new CharacterStat();
            cs.statId = ccs.statID;                        
            cs.statValue = ccs.statValue;
            cs.characterID = newCharacter.characterID;
            ydc.CharacterStats.InsertOnSubmit(cs);
        }                    

        var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID);
        foreach (var ccb in ccblst)
        {
            var charBody = new CharacterBody();
            charBody.bodyId = ccb.bodyId;
            charBody.bodyPartId = ccb.bodyPartId;
            charBody.characterID = newCharacter.characterID;
            ydc.CharacterBodies.InsertOnSubmit(charBody);
        }
        ydc.SubmitChanges();      
        created = true;

        transaction.Complete();
    }
    catch (Exception ex)
    {
        created = false;
    }
}
return created;

范例2:

    try
    {
        var newCharacter = new Character();
        newCharacter.characterName = chracterName;
        newCharacter.characterLevel = 1;
        newCharacter.characterExperience = 0;
        newCharacter.userUsername = userUsername;
        newCharacter.characterClassID = ccslst[0].characterClassID;

        ydc.Characters.InsertOnSubmit(newCharacter);

        foreach (var ccs in ccslst)
        {
            var cs = new CharacterStat();
            cs.statId = ccs.statID;                        
            cs.statValue = ccs.statValue;
            newCharacter.CharacterStats.Add(cs);
        }                    

        var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID);
        foreach (var ccb in ccblst)
        {
            var charBody = new CharacterBody();
            charBody.bodyId = ccb.bodyId;
            charBody.bodyPartId = ccb.bodyPartId;
            newCharacter.CharacterBodies.Add(charBody);
        }
        ydc.SubmitChanges();      
        created = true;
    }
    catch (Exception ex)
    {
        created = false;
    }

不知道语法,我是否将代码放在这个范围内:using(TransactionScope ts = new TransactionScope()){//我的代码}
Drahcir

2
您将要求DTC服务在部署计算机上运行才能使用TransactionScope执行事务。保持考虑。DTC:分布式事务处理协调器服务。
这个。__curious_geek 09年

@s_ruchit-实际上我不确定使用LINQ能否将其提升为分布式事务。由于数据上下文对所有提交使用相同的连接,因此我认为它将保持本地状态。这与使用TableAdapters时不同。
tvanfosson

@tvanfosson-如果您使用TransactionScope,则肯定需要DTC服务,但是如果使用LinqToSql,它将在Single Connection上执行所有操作,因此它不依赖于DTC。我更喜欢将TransactionScope置于第二优先级,因为它依赖于DTC。
这个。__curious_geek 09年

1
@flipdoubt,如果您使用的是Workflow Foundation,则使用System.Activities.Statements,否则使用System.Transactions
tvanfosson

41

使用LINQ to SQL时,您不需要执行显式的事务实现。默认情况下,所有数据库操作都包装在事务中。

例如:

AppDataContext db = new AppDataContext();

<In memory operation 1 on db>
<In memory operation 2 on db>
<In memory operation 3 on db>
<In memory operation 4 on db>

db.SubmitChanges();

.Net将db DataContext初始化和db.SubmitChanges()之间的所有操作包装在数据库事务周围,以确保您的数据库保持一致并在表之间维护属性完整性。

在这里阅读Scott Guthrie 的文章:-http : //weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx


但是需要一个在第一次提交更改时生成的ID,否则不知道如何获取ID。
Drahcir

4
请访问ScottGu撰写的文章。您可以不使用ID进行关联。这就是LINQ-to-SQL的优点。如果您不那样做,就不会利用Linq-To-Sql。我建议您阅读ScottGu的文章。您可以在我的答案中找到链接。
这个。__curious_geek 09年

是。看来您可以重写此代码而无需外部事务。我将更新我的答案。
tvanfosson

1
+1似乎LINQ to SQL在提交时为您解决了所有依赖关系。尼斯:)
satnhak 2011年

这意味着,如果某些更改导致失败,那么以前的所有更改都会回滚吗?
VSB
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.