Как установить CommandTimeout для DbContext?

Я ищу способ установить CommandTimeout для DbContext. После поиска я нашел способ, приведя DbContext в ObjectContext и установив значение для свойства CommandTimeout objectContext.

var objectContext = (this.DbContext as IObjectContextAdapter).ObjectContext;

но я должен работать с DbContext.

8 ответов


Он будет работать с вашим методом.

или подкласс (от форум msdn)

public class YourContext : DbContext
{
  public YourContext()
    : base("YourConnectionString")
  {
    // Get the ObjectContext related to this DbContext
    var objectContext = (this as IObjectContextAdapter).ObjectContext;

    // Sets the command timeout for all the commands
    objectContext.CommandTimeout = 120;
  }
}

Это может помочь вам.

public class MyContext : DbContext
{    
    public MyContext () : base(ContextHelper.CreateConnection("my connection string"), true)
    {
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
    }
}

var ctx = new DbContext();
ctx.Database.CommandTimeout = 120;

Я считаю, что изменение .TT файл работает для меня, как я не теряю изменения позже:

добавьте следующую строку:

((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;

сразу после создателя DbContext и до !погрузчик.IsLazy construct:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
<#
if (!loader.IsLazyLoadingEnabled(container))

затем он должен появиться в созданный контекст.cs:

public MyEntities()
            : base("name=MyEntities")
        {
            ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
        }

мне нравится подход расширения:

public static class DbContextExtensions
{
   public static void SetCommandTimeout(this ObjectContext dbContext,
       int TimeOut)
   {
       dbContext.CommandTimeout = TimeOut;
   }
}

и просто

((IObjectContextAdapter)cx).ObjectContext.SetCommandTimeout(300);

вот как я решил эту проблему при использовании файла EDMX. Это решение изменяет шаблон T4 по умолчанию, чтобы сгенерированный класс наследовался от пользовательского класса DbContext, который задает тайм-аут команды по умолчанию и свойство для его изменения.

я использую Visual Studio 2012 и EF 5.0. Ваш опыт может отличаться от других версий.

создайте пользовательский класс DbContext

public class CustomDbContext : DbContext
{
    ObjectContext _objectContext;

    public CustomDbContext( string nameOrConnectionString )
        : base( nameOrConnectionString )
    {
        var adapter = (( IObjectContextAdapter) this);

        _objectContext = adapter.ObjectContext;

        if ( _objectContext == null )
        {
            throw new Exception( "ObjectContext is null." );    
        }

        _objectContext.CommandTimeout = Settings.Default.DefaultCommandTimeoutSeconds;
    }

    public int? CommandTimeout
    {
        get
        {
            return _objectContext.CommandTimeout;
        }
        set
        {
            _objectContext.CommandTimeout = value;
        }
    }
}

это имеет необязательную функцию: я не жестко кодирую тайм-аут команды по умолчанию. Вместо этого я загружаю его из настроек проекта, чтобы изменить значение в файле конфигурации. Как настроить и использовать параметры проекта не входит в область этого ответа.

Я также не жестко кодирую строку подключения или имя строки подключения. Он уже передан в конструктор сгенерированным классом context, поэтому нет смысла жестко кодировать его здесь. Это ничего нового; файл EDMX уже генерирует следующий конструктор для вас, поэтому мы просто передаем ценность.

public MyEntities()
    : base("name=MyEntities")
{
}

(это указывает EF загрузить строку подключения с именем "MyEntities" из файла конфигурации.)

Я бросаю пользовательское исключение, если ObjectContext всегда равно null. Я не думаю, что это когда-нибудь будет, но это более значимо, чем получить NullReferenceException.

Я храню ObjectContext в поле, чтобы я мог сделать свойство для доступа к нему, чтобы переопределить значение по умолчанию.

изменение контекста сущности T4 шаблон

в обозревателе решений разверните файл EDMX, чтобы увидеть шаблоны T4. У них есть .расширение tt.

дважды щелкните "MyModel.Контекст.TT " файл, чтобы открыть его. Вокруг строки 57 вы должны увидеть следующее:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext

эта строка шаблона генерирует определение класса вашего класса "MyEntities", который наследует DbContext.

измените строку так, чтобы созданный класс наследовал CustomDbContext, вместо этого:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : CustomDbContext

как только вы сохраните этот файл, он должен регенерировать класс. Если нет, вы можете щелкнуть правой кнопкой мыши файл EDMX и выбрать "запустить пользовательский инструмент". Если развернуть " MyModel.Контекст.TT "файл под файлом EDMX, вы увидите" MyModel.Контекст.цезий." Это сгенерированный файл. Откройте его, и вы увидите, что он теперь наследует CustomDbContext.

public partial class MyEntities : CustomDbContext

вот и все.

вопросы

после изменения контекста класса DbContext to CustomDbContext, Visual Studio выдаст вам ошибку, если вы попытаетесь добавить новый класс контроллера MVC, используя шаблон "контроллер с действиями чтения/записи и представлениями, используя Entity Framework". Он скажет: "неподдерживаемый тип контекста.". Чтобы обойти это, откройте сгенерированную " MyModel.Контекст.cs " класс, и временно изменить тип, который он наследует обратно в DbContext. После добавления нового контроллера вы можете изменить его на CustomDbContext.


Если это может помочь, это VB.Net решение:

Dim objectContext As Objects.ObjectContext = CType(Me,IObjectContextAdapter).ObjectContext
objectContext.commandTimeout = connectionTimeout

Я пришел сюда в поисках примера установки тайм-аута для одной команды, а не такой глобальной настройки.

Я полагаю, что это, вероятно, поможет кому-то иметь пример того, как я достиг этого:

var sqlCmd = new SqlCommand(sql, context.Database.Connection as SqlConnection);
sqlCmd.Parameters.Add(idParam);
sqlCmd.CommandTimeout = 90;

if (sqlCmd.Connection.State == System.Data.ConnectionState.Closed)
{
    sqlCmd.Connection.Open();
}
sqlCmd.ExecuteNonQuery();
sqlCmd.Connection.Close();