EF: How do I call SaveChanges twice inside a transaction?

 ̄綄美尐妖づ 提交于 2019-11-27 14:00:44

问题


Using Entity Framework (code first in my case), I have an operation that requires me to call SaveChanges to update one object in the DB, and then SaveChanges again to update another object. (I need the first SaveChanges to resolve an issue where EF can't figure out which object to update first).

I tried doing:

using (var transaction = new TransactionScope())
{
    // Do something

    db.SaveChanges();

    // Do something else

    db.SaveChanges();

    tramsaction.Complete();
}

When I run that, I get an exception at the second SaveChanges call, saying "the underlying provider failed on open". The inner exception says that MSDTC is not enabled on my machine.

Now, I've seen posts elsewhere that describe how to enable MSDTC, but it seems that I would also need to enable network access, etc. This sounds like complete overkill here, since there are no other databases involved, let alone other servers. I don't want to do something that's going to make my whole application less secure (or slower).

Surely there must be a more lightweight way of doing this (ideally without MSDTC)?!


回答1:


It is probably caused by two different connections used in your transaction. Try to control connection for your operation manually:

var objectContext = ((IObjectContextAdapter)db).ObjectContext;

try {
    object.Context.Connection.Open();
    using (var transaction = new TransactionScope()) {
        // Do something

        db.SaveChanges();

        // Do something else

        db.SaveChanges();

        transaction.Complete();
    }
} finally {
    objectContext.Connection.Close();
} 



回答2:


I know it's kind of late answer but i found it useful to share.

Now in EF6 it's easier to acheeve this by using dbContext.Database.BeginTransaction()

like this :

using (var context = new BloggingContext())
{
    using (var dbContextTransaction = context.Database.BeginTransaction())
    {
        try
        {
            // do your changes
            context.SaveChanges();

            // do another changes
            context.SaveChanges();

            dbContextTransaction.Commit();
        }
        catch (Exception)
        {
            dbContextTransaction.Rollback();
        }
    }
}

for more information look at this

again it's in EF6 Onwards




回答3:


By calling SaveChanges() as you are is causing the data to be persisted to the database and the EF to forget about the changes it just made.

The trick is to use SaveChanges(false) so that the changes are persisted to the DB but EF doesn't forget the changes it makes thus making logging / retrying possible.

        var scope = new TransactionScope(
            TransactionScopeOption.RequiresNew,
            new TransactionOptions() { IsolationLevel = IsolationLevel.Serializable }
        );

        using (scope)
        {
            Entities context1 = new Entities();
            // Do Stuff
            context1.SaveChanges(false);

            Entities context2 = new Entities();
            // Do Stuff
            context2.SaveChanges(false);

            scope.Complete();
            context1.AcceptAllChanges();
            context2.AcceptAllChanges();
        }

P.S. As soon as you have more than one connection open inside transactionscope it WILL escalate to DTC.




回答4:


For the final answer selected above, there is a typo. Corrected line below:

objectContext.Connection.Open();

Also, need to add references for System.Data.Entity.Infrastructure and System.Transactions



来源:https://stackoverflow.com/questions/12809958/ef-how-do-i-call-savechanges-twice-inside-a-transaction

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!