Entity Framework Timeouts


324

ฉันได้รับไทม์เอาต์โดยใช้ Entity Framework (EF) เมื่อใช้การนำเข้าฟังก์ชั่นที่ใช้เวลาดำเนินการมากกว่า 30 วินาที ฉันลองสิ่งต่อไปนี้และไม่สามารถแก้ไขปัญหานี้ได้:

ฉันเพิ่มDefault Command Timeout=300000สตริงการเชื่อมต่อในApp.Configไฟล์ในโครงการที่มีไฟล์ EDMX เป็นข้อเสนอแนะที่นี่

นี่คือลักษณะของสตริงการเชื่อมต่อของฉัน:

<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" />

ฉันพยายามตั้งค่า CommandTimeout ในที่เก็บของฉันโดยตรงเช่น:

private TrekEntities context = new TrekEntities();

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

ฉันจะทำอะไรได้อีกเพื่อให้ EF หมดเวลา? สิ่งนี้จะเกิดขึ้นสำหรับชุดข้อมูลที่มีขนาดใหญ่มากเท่านั้น ทุกอย่างทำงานได้ดีกับชุดข้อมูลขนาดเล็ก

นี่เป็นหนึ่งในข้อผิดพลาดที่ฉันได้รับ:

System.Data.EntityCommandExecutionException: มีข้อผิดพลาดเกิดขึ้นขณะดำเนินการกำหนดคำสั่ง ดูข้อยกเว้นภายในสำหรับรายละเอียด ---> System.Data.SqlClient.SqlException: การหมดเวลาหมดอายุแล้ว รอบระยะเวลาการหมดเวลาผ่านไปก่อนที่การดำเนินการจะเสร็จสิ้นหรือเซิร์ฟเวอร์ไม่ตอบสนอง


ตกลง - ฉันทำงานนี้และมันโง่ที่เกิดขึ้น ฉันมีทั้งสตริงการเชื่อมต่อด้วยDefault Command Timeout=300000และ CommandTimeout ตั้งค่าเป็น 180 เมื่อฉันลบออกDefault Command Timeoutจากสตริงการเชื่อมต่อมันทำงานได้ ดังนั้นคำตอบคือการตั้งค่า CommandTimeout ด้วยตนเองในที่เก็บของคุณบนวัตถุบริบทของคุณเช่น:

this.context.CommandTimeout = 180;

เห็นได้ชัดว่าการตั้งค่าการหมดเวลาในสตริงการเชื่อมต่อไม่มีผลกับมัน


ลบ & quot; จากสตริงการเชื่อมต่อ
Brian Webster

อ้างถึงสิ่งนี้เช่นกันstackoverflow.com/questions/4396833/sql-exception-with-net-4-ef
Saif Khan

5
@ hamlin11 ในสตริงการเชื่อมต่อของ EF นั้นจำเป็นต้องมีเพื่อกำหนดว่าส่วนใดคือสตริงการเชื่อมต่อและส่วนใดคือข้อมูลเมตาของ EF ทิ้ง&quot;ไว้ในสตริง
Chev

2
คำแนะนำของฉันคือก่อนที่คุณจะเพิ่มการหมดเวลาในการตรวจสอบก่อนเพื่อดูว่าเหตุใด EF จึงหมดเวลา ในกรณีของเราเราตระหนักว่าเราจำเป็นต้องเพิ่มNONCLUSTEREDดัชนีลงในตารางบางส่วนสิ่งนี้แก้ไขปัญหาการหมดเวลาสำหรับเรา
zulucoda

ฉันทำงานกับการสนับสนุน MS ในปัญหาการหมดเวลาของ SQL - นี่คือเมื่อฐานข้อมูลโฮสต์ใน SQL Azure ฉันบอกบริการ Azure PaaS ทั้งหมด (เว็บไซต์ PaaS และ SQL Azure เป็นต้น) มีการหมดเวลาแบบสากลที่ 230 วินาทีและสิ่งนี้สำคัญกว่าเสมอแม้ว่าคุณจะตั้งค่าการหมดเวลาด้วยตนเอง นี่คือการปกป้องทรัพยากรของโครงสร้างพื้นฐาน PaaS
Ian Robertson

คำตอบ:


552

มีข้อผิดพลาดที่ทราบพร้อมระบุการหมดเวลาคำสั่งเริ่มต้นภายในสตริงการเชื่อมต่อของ EF

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

ลบค่าออกจากสายอักขระการเชื่อมต่อและตั้งค่าบนวัตถุบริบทข้อมูลเอง สิ่งนี้จะทำงานหากคุณลบค่าที่ขัดแย้งกันออกจากสตริงการเชื่อมต่อ

Entity Framework Core 1.0:

this.context.Database.SetCommandTimeout(180);

เอนทิตีกรอบ 6:

this.context.Database.CommandTimeout = 180;

Entity Framework 5:

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

Entity Framework 4 และด้านล่าง:

this.context.CommandTimeout = 180;

5
ฉันจะทำให้สิ่งนี้สำเร็จโดยใช้ edmx ได้อย่างไร
iroel

2
EntityFramework เวอร์ชันนี้แก้ไขได้หรือไม่ ฉันหาข้อผิดพลาดของ EF ไม่พบ
rudimenter

7
ฉันไม่เชื่อว่านี่เป็นข้อผิดพลาด แต่จากการออกแบบให้ดูที่ลิงก์
Mick P

3
เนื่องจากการตั้งค่าบางอย่างมีค่าเป็น ms และบางค่าใน s ฉันจึงค้นหาที่นี่ CommandTimeout เป็นวินาที
JabberwockyDecompiler

6
ใน Entity Framework 7 คุณสามารถตั้งค่านี้ใน Constructor ของ DbContext / IdentityDbContext:this.Database.SetCommandTimeout(180);
Thomas Hagström

101

หากคุณใช้ DbContext ให้ใช้ตัวสร้างต่อไปนี้เพื่อตั้งค่าการหมดเวลาของคำสั่ง:

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

3
@ErickPetru ดังนั้นคุณสามารถเปลี่ยนเป็นจำนวนนาทีที่แตกต่างกันได้อย่างง่ายดาย :) นอกจากนี้ฉันจะไม่แปลกใจถ้าคอมไพเลอร์ปรับการคูณให้ดีที่สุด!
Joel Verhagen

2
@ JoelVerhagen ไม่ต้องแปลกใจ นี่คือคำอธิบายที่ดีของการเพิ่มประสิทธิภาพเมื่อรถยนต์เกิดขึ้น: stackoverflow.com/questions/160848/... ในกรณีนี้ฉันคิดว่าแม้จะเกิดขึ้น (เพราะมันมีค่าสองตัวอักษร) แต่โดยสุจริตฉันคิดว่ารหัสนี้เป็นวิธีที่แปลก
Erick Petrucelli

33
ฉัน ... เด็ก ๆ กำลังหิวโหย ... ใครจะสนใจ 1 * 60?
Timmerz

9
@ErikPetru นี่เป็นเรื่องธรรมดามากและทำให้โค้ดอ่านง่ายขึ้น
Calvin

อะไรคือวิธีที่ดีที่สุดในการจัดการสิ่งนี้เนื่องจากDbContextคลาสที่ฉันได้รับมานั้นสร้างโดยอัตโนมัติจากedmxไฟล์
Matt Burland

41

หากคุณกำลังใช้DbContextและ EF v6 + หรือคุณสามารถใช้:

this.context.Database.CommandTimeout = 180;

13

ฉันมักจะจัดการกับการดำเนินงานของฉันภายในการทำธุรกรรม ดังที่ฉันเคยพบมามันไม่เพียงพอที่จะตั้งค่าไทม์เอาต์ของคำสั่งบริบท แต่ทรานแซคชันต้องการตัวสร้างที่มีพารามิเตอร์ไทม์เอาต์ ฉันต้องตั้งค่าการหมดเวลาทั้งสองเพื่อให้มันทำงานได้อย่างถูกต้อง

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

ในตอนท้ายของฟังก์ชั่นฉันตั้งค่าการหมดเวลาคำสั่งกลับเป็นค่าก่อนหน้าในภายหลัง

ใช้ EF6


ไม่ใช่วิธีการที่ดีเลย ฉันเคยเพิ่มขอบเขตธุรกรรมจำนวนมากและมันกลายเป็นฝันร้ายสำหรับฉันในโครงการ เปลี่ยนขอบเขตการทำธุรกรรมทั้งหมดด้วย SAVEChanges () ใน EF 6+ ในที่สุด ตรวจสอบcoderwall.com/p/jnniww/
ดวงจันทร์

คำตอบนี้ควรมีคะแนนโหวตสูงกว่า ฉันลองวิธีที่แตกต่างกันทั้งหมดเพื่อเพิ่มการหมดเวลา แต่เฉพาะเมื่อฉันตั้งค่าการหมดเวลาของบริบทคำสั่งทั้งสองและขอบเขตของธุรกรรมจากนั้นก็ใช้งานได้
Gang

3

ฉันรู้ว่านี่เป็นเธรดที่เก่ามากที่ใช้งานได้ แต่ถึงกระนั้น EF ก็ยังไม่ได้แก้ไขสิ่งนี้ สำหรับผู้ที่ใช้สร้างอัตโนมัติDbContextสามารถใช้รหัสต่อไปนี้เพื่อตั้งค่าการหมดเวลาด้วยตนเอง

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

หากคุณใช้ Entity Framework อย่างฉันคุณควรกำหนด Time Out ในคลาส Startup ดังนี้

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

1

นี่คือสิ่งที่ฉันให้ทุน อาจจะช่วยใครซักคน:

ดังนั้นเราไปที่นี่:

หากคุณใช้ LINQ กับ EF เพื่อค้นหาองค์ประกอบที่แน่นอนที่มีอยู่ในรายการดังนี้:

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

ทุกอย่างกำลังดีจนกระทั่ง IdList มีมากกว่าหนึ่ง Id

ปัญหา“ หมดเวลา” เกิดขึ้นหากรายการมี ID เพียง ID เดียว เพื่อแก้ไขปัญหาใช้ถ้าเงื่อนไขในการตรวจสอบจำนวนรหัสใน IdList

ตัวอย่าง:

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();
}

คำอธิบาย:

เพียงลองใช้ Sql Profiler และตรวจสอบคำสั่ง Select ที่สร้างขึ้นโดย Entity frameeork ...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.