1
votes

Today I faced strange issue with Entity Framework. Consider following class:

public partial class Entities
{
 ...
 public void DocumentUpdateForSync(string userLogin, IEntrySync document)
 {
    var timeEntry = document as Domain.Documents.TimeEntry;        
    Database.BeginTransaction();                
            try
            {

                mobileTimeEntryUpdate(userLogin,
                                      timeEntry.Id,
                                      timeEntry.ProjectId,
                                      timeEntry.ActivityTypeId,
                                      timeEntry.FileAs,
                                      timeEntry.StartTime,
                                      timeEntry.Duration,
                                      timeEntry.Comments,                                          
                                     readAfterUpdate:false).FirstOrDefault();                    
            }
            catch (Exception e)
            {
                //Here Database.CurrentTransaction becomes null
                //I want to handle errors silently, not rolling back transaction
            }
             ...
             Database.CurrentTransaction?.Commit();
 }

}

This class is part of autogenerated class, that is created by EF. It inherits from DbContext class. mobileTimeEntryUpdate method is autogenerated wrapper for stored procedure:

public virtual ObjectResult<mobileTimeEntryGet_Result> mobileTimeEntryUpdate(string userLogin, Nullable<int> iD, Nullable<int> projectID, Nullable<int> activityTypeID, string fileAs, Nullable<System.DateTime> startTime, Nullable<int> duration, string comments, Nullable<bool> readAfterUpdate)
    {
        var userLoginParameter = userLogin != null ?
            new ObjectParameter("UserLogin", userLogin) :
            new ObjectParameter("UserLogin", typeof(string));

        var iDParameter = iD.HasValue ?
            new ObjectParameter("ID", iD) :
            new ObjectParameter("ID", typeof(int));

        var projectIDParameter = projectID.HasValue ?
            new ObjectParameter("ProjectID", projectID) :
            new ObjectParameter("ProjectID", typeof(int));

        var activityTypeIDParameter = activityTypeID.HasValue ?
            new ObjectParameter("ActivityTypeID", activityTypeID) :
            new ObjectParameter("ActivityTypeID", typeof(int));

        var fileAsParameter = fileAs != null ?
            new ObjectParameter("FileAs", fileAs) :
            new ObjectParameter("FileAs", typeof(string));

        var startTimeParameter = startTime.HasValue ?
            new ObjectParameter("StartTime", startTime) :
            new ObjectParameter("StartTime", typeof(System.DateTime));

        var durationParameter = duration.HasValue ?
            new ObjectParameter("Duration", duration) :
            new ObjectParameter("Duration", typeof(int));

        var commentsParameter = comments != null ?
            new ObjectParameter("Comments", comments) :
            new ObjectParameter("Comments", typeof(string));

        var readAfterUpdateParameter = readAfterUpdate.HasValue ?
            new ObjectParameter("ReadAfterUpdate", readAfterUpdate) :
            new ObjectParameter("ReadAfterUpdate", typeof(bool));

        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<mobileTimeEntryGet_Result>("mobileTimeEntryUpdate", userLoginParameter, iDParameter, projectIDParameter, activityTypeIDParameter, fileAsParameter, startTimeParameter, durationParameter, commentsParameter, readAfterUpdateParameter);
    }

So the stored procedure can throw some errors, which I want to catch silently (I plan to save the exception detail in some object and pass it to caller).

But when exception occurs the transaction becomes null and I cant commit it.

Can someone suggest - what is the cause of such behaviour? And how it can be avoided? Thanks

Update

Here is stack trace:

System.Data.Entity.Core.EntityCommandExecutionException: Произошла ошибка при выполнении определения команды. Дополнительные сведения приведены во внутреннем исключении. ---> System.Data.SqlClient.SqlException: #accessdenied The transaction ended in the trigger. The batch has been aborted. в System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) в System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) в System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) в System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) в System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() в System.Data.SqlClient.SqlDataReader.get_MetaData() в System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption) в System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) в System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) в System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) в System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) в System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) в System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) в System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext1 c) в System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func3 operation, TInterceptionContext interceptionContext, Action3 executing, Action3 executed) в System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext) в System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior) в System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) в System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) --- Конец трассировки внутреннего стека исключений --- в System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) в System.Data.Entity.Core.Objects.ObjectContext.CreateFunctionObjectResult[TElement](EntityCommand entityCommand, ReadOnlyCollection1 entitySets, EdmType[] edmTypes, ExecutionOptions executionOptions) в System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass471.b__46() в System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) в System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass471.b__45() в System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func1 operation) в System.Data.Entity.Core.Objects.ObjectContext.ExecuteFunction[TElement](String functionName, ExecutionOptions executionOptions, ObjectParameter[] parameters) в System.Data.Entity.Core.Objects.ObjectContext.ExecuteFunction[TElement](String functionName, MergeOption mergeOption, ObjectParameter[] parameters) в System.Data.Entity.Core.Objects.ObjectContext.ExecuteFunction[TElement](String functionName, ObjectParameter[] parameters) в ******.Entities.mobileTimeEntryUpdate(String userLogin, Nullable1 iD, Nullable1 projectID, Nullable1 activityTypeID, String fileAs, Nullable1 startTime, Nullable1 duration, String comments, Nullable`1 readAfterUpdate) в ******\DbModel.Context.cs:строка 186 в ******.Entities.DocumentUpdateForSync(String userLogin, IEntrySync document) в *******\Entities.cs:строка 125

2
What is the exception you are getting?bman7716
Please post the exception stack.JuanR

2 Answers

2
votes

Assuming SQL Server, some errors will doom or rollback the transaction. See this classic (but still relevant) article Error Handling in SQL 2000 – a Background.

0
votes

Oh, sorry, I must read exception message carefully - "The transaction ended in the trigger" - it means that stored procedure made some changes to tables which called trigger. And this trigger due to some logic rolled back transaction. I think this is the cause of described behaviour.