31

How can I set the command timeout of a DbContext?

MikeWyatt
  • 7,842
  • 10
  • 50
  • 71

5 Answers5

74

I found this solution after another Google search. You can access the ObjectContext for a DbContext by casting this to an IObjectContextAdapter.

From http://social.msdn.microsoft.com/Forums/en-ZA/adodotnetentityframework/thread/6fe91a64-0208-4ab8-8667-d061af340994:

public class MyContext : DbContext
{
    public MyContext ()
        : base(ContextHelper.CreateConnection("my connection string"), true)
    {
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
    }
}
MikeWyatt
  • 7,842
  • 10
  • 50
  • 71
  • MikeWyatt answer is helpful, but you may run into trouble when you apply this "hack" in projects that already use Entity Framework, and in those projects you use EntityDataSource with DefaultContainerName property specified. –  Dec 14 '12 at 11:58
  • Be careful if you use any Initializers (Database.SetInitializer(...). The initializer will be called by the this.ObjectContext getter – Alexander Bartosh Jan 31 '13 at 08:32
  • @AlexanderBartosh: Can you elaborate on what the problem might be? I use `Database.SetInitializer()`. What should I be careful of? – hofnarwillie May 16 '13 at 15:05
7

A better solution to this for later versions of Entity Framework is to use the DbContext.Database.CommandTimeout property. I think this came in with EF 6.

Josh Gallagher
  • 5,211
  • 2
  • 33
  • 60
0

Please try the following code before you execute any DB command. The following Code need 3/4 minute to execute. So, CommandTimeout set 300 (in seconds) before execution of the command.

public List<CollectionEfficiencyByUnitOfficeSummary> ReadCollectionEfficiencyByUnitOfficeSummary(string yearMonth, string locationCode, string reportType)
        {
            ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext.CommandTimeout = 300;
            return context.CollectionEfficiencyByUnitOfficeSummary(yearMonth, locationCode, reportType).ToList();
        }
Md. Nazrul Islam
  • 2,809
  • 26
  • 31
0

I have had the same problem running EntityFramework v4.4 with CodeFirstStoredProc v2.2. Upgrading was not an option for me so I had to update the CodeFirstStoredProcs.cs file to take in a new nullable int parameter called "commandTimeout" into the following 3 methods as shown below.

public static ResultsList CallStoredProc<T>(this DbContext context, StoredProc<T> procedure, T data, int? commandTimeout = null)
    {
        IEnumerable<SqlParameter> parms = procedure.Parameters(data);
        ResultsList results = context.ReadFromStoredProc(procedure.fullname, parms, commandTimeout, procedure.returntypes);
        procedure.ProcessOutputParms(parms, data);
        return results ?? new ResultsList();
    }

public static ResultsList CallStoredProc(this DbContext context, StoredProc procedure, IEnumerable<SqlParameter> parms = null, int? commandTimeout = null)
    {
        ResultsList results = context.ReadFromStoredProc(procedure.fullname, parms, commandTimeout, procedure.returntypes);
        return results ?? new ResultsList();
    }

In the method below, this is where a condition to check the parameter and apply the cmd.connectionTimeout value.

internal static ResultsList ReadFromStoredProc(this DbContext context,
        String procname,
        IEnumerable<SqlParameter> parms = null,
        int? commandTimeout = null,
        params Type[] outputtypes)
    {
        // create our output set object
        ResultsList results = new ResultsList();

        // ensure that we have a type list, even if it's empty
        IEnumerator currenttype = (null == outputtypes) ?
            new Type[0].GetEnumerator() :
            outputtypes.GetEnumerator();

        // handle to the database connection object
        var connection = (SqlConnection)context.Database.Connection;
        try
        {
            // open the connect for use and create a command object
            connection.Open();
            using (var cmd = connection.CreateCommand())
            {
                // command to execute is our stored procedure
                cmd.CommandText = procname;
                cmd.CommandType = System.Data.CommandType.StoredProcedure;

                if (commandTimeout.HasValue)
                {
                    cmd.CommandTimeout = commandTimeout.Value;
                }

                // move parameters to command object
                if (null != parms)
                    foreach (SqlParameter p in parms)
                        cmd.Parameters.Add(p);
                //    foreach (ParameterHolder p in parms)
                //        cmd.Parameters.Add(p.toParameter(cmd));

                // Do It! This actually makes the database call
                var reader = cmd.ExecuteReader();

                // get the type we're expecting for the first result. If no types specified,
                // ignore all results
                if (currenttype.MoveNext())
                {
                    // process results - repeat this loop for each result set returned by the stored proc
                    // for which we have a result type specified
                    do
                    {
                        // get properties to save for the current destination type
                        PropertyInfo[] props = ((Type)currenttype.Current).GetMappedProperties();

                        // create a destination for our results
                        List<object> current = new List<object>();

                        // process the result set
                        while (reader.Read())
                        {
                            // create an object to hold this result
                            object item = ((Type)currenttype.Current).GetConstructor(System.Type.EmptyTypes).Invoke(new object[0]);

                            // copy data elements by parameter name from result to destination object
                            reader.ReadRecord(item, props);

                            // add newly populated item to our output list
                            current.Add(item);
                        }

                        // add this result set to our return list
                        results.Add(current);
                    }
                    while (reader.NextResult() && currenttype.MoveNext());
                }
                // close up the reader, we're done saving results
                reader.Close();
            }
        }
        catch (Exception ex)
        {
            throw new Exception("Error reading from stored proc " + procname + ": " + ex.Message, ex);
        }
        finally
        {
            connection.Close();
        }

        return results;
    }
}

I hope this help as I was looking around for help but found nothing, not until I realised that I could do so without updating versions of CodeFirstStoredProcs that forces me to update EntityFramework as well.

InitialV
  • 96
  • 1
  • 5
-8

If you're using SqlServer, just add this to your connection string: "... Connect Timeout = x" Where x is the timeout in ms.

David Anderson
  • 623
  • 5
  • 22