Batas Waktu Kerangka Entitas


324

Saya mendapatkan batas waktu menggunakan Entity Framework (EF) saat menggunakan fungsi impor yang membutuhkan waktu lebih dari 30 detik untuk menyelesaikannya. Saya mencoba yang berikut ini dan belum dapat menyelesaikan masalah ini:

Saya menambahkan Default Command Timeout=300000ke string koneksi di file App.Config dalam proyek yang memiliki file EDMX seperti yang disarankan di sini .

Seperti inilah string koneksi saya:

<add 
    name="MyEntityConnectionString" 
    connectionString="metadata=res://*/MyEntities.csdl|res://*/MyEntities.ssdl|
       res://*/MyEntities.msl;
       provider=System.Data.SqlClient;provider connection string=&quot;
       Data Source=trekdevbox;Initial Catalog=StarTrekDatabase;
       Persist Security Info=True;User ID=JamesTKirk;Password=IsFriendsWithSpock;
       MultipleActiveResultSets=True;Default Command Timeout=300000;&quot;"
    providerName="System.Data.EntityClient" />

Saya mencoba mengatur CommandTimeout di repositori saya secara langsung seperti:

private TrekEntities context = new TrekEntities();

public IEnumerable<TrekMatches> GetKirksFriends()
{
    this.context.CommandTimeout = 180;
    return this.context.GetKirksFriends();
}

Apa lagi yang bisa saya lakukan untuk mengeluarkan EF dari waktu habis? Ini hanya terjadi untuk dataset yang sangat besar. Semuanya berfungsi baik dengan dataset kecil.

Inilah salah satu kesalahan yang saya dapatkan:

System.Data.EntityCommandExecutionException: Terjadi kesalahan saat menjalankan definisi perintah. Lihat pengecualian dalam untuk detailnya. ---> System.Data.SqlClient.SqlException: Batas waktu kedaluwarsa. Periode waktu habis berlalu sebelum penyelesaian operasi atau server tidak merespons.


OK - saya berhasil dan ini konyol apa yang terjadi. Saya memiliki string koneksi dengan Default Command Timeout=300000dan CommandTimeout diatur ke 180. Ketika saya menghapus Default Command Timeoutdari string koneksi, itu berhasil. Jadi jawabannya adalah secara manual mengatur CommandTimeout di repositori Anda pada objek konteks Anda seperti:

this.context.CommandTimeout = 180;

Tampaknya pengaturan pengaturan batas waktu dalam string koneksi tidak berpengaruh padanya.


Hapus & quot; dari string koneksi
Brian Webster


5
@ hamlin11 Dalam string koneksi EF, yang diperlukan untuk menentukan bagian mana yang merupakan string koneksi dan bagian mana yang merupakan metadata EF. Biarkan &quot;dalam string.
Chev

2
saran saya adalah sebelum Anda menambah batas waktu untuk menyelidiki terlebih dahulu untuk mengetahui mengapa EF kehabisan waktu. Dalam kasus kami, kami menyadari bahwa kami perlu menambahkan NONCLUSTEREDindeks ke beberapa tabel, ini menyelesaikan masalah batas waktu bagi kami.
zulucoda

Saya bekerja dengan dukungan MS pada masalah batas waktu SQL - ini adalah ketika DB di-host di SQL Azure. Saya diberitahu semua layanan Azure PaaS (situs PaaS dan SQL Azure dll) ada batas waktu universal 230 detik, dan ini selalu diutamakan, bahkan jika Anda menetapkan batas waktu secara manual. Ini untuk melindungi sumber daya infrastruktur PaaS multi-tenant.
Ian Robertson

Jawaban:


552

Ada bug yang dikenal dengan menentukan batas waktu perintah default dalam string koneksi EF.

http://bugs.mysql.com/bug.php?id=56806

Hapus nilai dari string koneksi dan atur pada objek konteks data itu sendiri. Ini akan berfungsi jika Anda menghapus nilai yang bertentangan dari string koneksi.

Kerangka Entitas Inti 1.0:

this.context.Database.SetCommandTimeout(180);

Kerangka Entitas 6:

this.context.Database.CommandTimeout = 180;

Kerangka Entitas 5:

((IObjectContextAdapter)this.context).ObjectContext.CommandTimeout = 180;

Kerangka Entitas 4 dan di bawah ini:

this.context.CommandTimeout = 180;

5
Bagaimana saya bisa mencapai ini menggunakan edmx?
iroel

2
Di versi EntityFramework mana ini diperbaiki? Saya tidak dapat menemukan bug EF untuk itu.
rudimenter

7
Saya tidak percaya ini adalah bug, tetapi lebih karena desain, lihat bagian Keterangan di sini tautan
Mick P

3
Karena beberapa pengaturan dalam ms dan beberapa dalam s, saya mencarinya di sini , CommandTimeout dalam hitungan detik.
JabberwockyDecompiler

6
Di Entity Framework 7 Anda dapat mengatur ini di konstruktor DbContext / IdentityDbContext:this.Database.SetCommandTimeout(180);
Thomas Hagström

101

Jika Anda menggunakan DbContext, gunakan konstruktor berikut untuk mengatur batas waktu perintah:

public class MyContext : DbContext
{
    public MyContext ()
    {
        var adapter = (IObjectContextAdapter)this;
        var objectContext = adapter.ObjectContext;
        objectContext.CommandTimeout = 1 * 60; // value in seconds
    }
}

3
@ ErickPetru, jadi Anda dapat dengan mudah mengubahnya ke jumlah menit yang berbeda :), juga saya tidak akan terlalu terkejut jika kompiler mengoptimalkan perkalian itu!
Joel Verhagen

2
@ JoelVerhagen, jangan kaget. Berikut adalah penjelasan yang baik tentang kapan optimasi otomatis terjadi: stackoverflow.com/questions/160848/… . Dalam hal ini, saya kira itu bahkan terjadi (karena mereka adalah dua nilai literal), tetapi jujur ​​saya pikir kode ini agak aneh dengan cara ini.
Erick Petrucelli

33
meh ... anak-anak kelaparan ... siapa yang peduli dengan 1 * 60?
Timmerz

9
@ErikPetru, ini sebenarnya praktik yang sangat umum dan membuat kode lebih mudah dibaca.
Calvin

Apa cara terbaik untuk menangani ini mengingat DbContextkelas turunan saya dibuat secara otomatis dari sebuah edmxfile?
Matt Burland

41

Jika Anda menggunakan DbContextdan EF v6 +, Anda juga dapat menggunakan:

this.context.Database.CommandTimeout = 180;

13

Biasanya saya menangani operasi saya dalam suatu transaksi . Seperti yang saya alami, tidak cukup untuk mengatur batas waktu perintah konteks, tetapi transaksi membutuhkan konstruktor dengan parameter batas waktu. Saya harus menetapkan kedua nilai time out agar berfungsi dengan benar.

int? prevto = uow.Context.Database.CommandTimeout;
uow.Context.Database.CommandTimeout = 900;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(900))) {
...
}

Di akhir fungsi saya mengatur kembali perintah timeout ke nilai sebelumnya di prevto.

Menggunakan EF6


Bukan pendekatan yang baik sama sekali. Saya dulu menambahkan banyak ruang lingkup transaksi dan itu menjadi mimpi buruk bagi saya dalam sebuah proyek. Akhirnya mengganti semua ruang lingkup transaksi dengan SAVEC tunggal () di EF 6+. Periksa coderwall.com/p/jnniww/…
Bulan ini

Jawaban ini harus memiliki suara yang lebih tinggi. Saya mencoba semua cara yang berbeda untuk meningkatkan batas waktu tetapi hanya ketika saya mengatur batas waktu perintah KEDUA konteks dan transaksi maka itu berhasil.
Geng

3

Saya tahu ini adalah thread yang sangat lama berjalan, tetapi EF masih belum memperbaikinya. Bagi orang yang menggunakan yang dibuat secara otomatis DbContextdapat menggunakan kode berikut untuk mengatur batas waktu secara manual.

public partial class SampleContext : DbContext
{
    public SampleContext()
        : base("name=SampleContext")
    {
        this.SetCommandTimeOut(180);
    }

    public void SetCommandTimeOut(int Timeout)
    {
        var objectContext = (this as IObjectContextAdapter).ObjectContext;
        objectContext.CommandTimeout = Timeout;
    }

3

Jika Anda menggunakan Entity Framework seperti saya, Anda harus mendefinisikan Time out pada kelas Startup sebagai berikut:

 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), o => o.CommandTimeout(180)));

1

Inilah yang saya danai. Mungkin itu akan membantu seseorang:

Jadi di sini kita mulai:

Jika Anda menggunakan LINQ dengan EF mencari beberapa elemen tepat yang ada dalam daftar seperti ini:

await context.MyObject1.Include("MyObject2").Where(t => IdList.Contains(t.MyObjectId)).ToListAsync();

semuanya berjalan dengan baik sampai IdList berisi lebih dari satu Id.

Masalah "batas waktu" muncul jika daftar hanya berisi satu Id. Untuk mengatasi masalah ini gunakan jika kondisi untuk memeriksa jumlah id di IdList.

Contoh:

if (IdList.Count == 1)
{
    result = await entities. MyObject1.Include("MyObject2").Where(t => IdList.FirstOrDefault()==t. MyObjectId).ToListAsync();
}
else
{
    result = await entities. MyObject1.Include("MyObject2").Where(t => IdList.Contains(t. MyObjectId)).ToListAsync();
}

Penjelasan:

Cukup coba gunakan Sql Profiler dan periksa pernyataan Select yang dihasilkan oleh Entity frameeork. ...

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.