c# - SqlException من Entity Framework-غير مسموح بالمعاملة الجديدة بسبب وجود سلاسل عمليات أخرى قيد التشغيل في الجلسة




entity-framework transactions (12)

أتلقى حاليًا هذا الخطأ:

System.Data.SqlClient.SqlException: غير مسموح بالمعاملات الجديدة بسبب وجود سلاسل عمليات أخرى قيد التشغيل في الجلسة.

أثناء تشغيل هذا الكود:

public class ProductManager : IProductManager
{
    #region Declare Models
    private RivWorks.Model.Negotiation.RIV_Entities _dbRiv = RivWorks.Model.Stores.RivEntities(AppSettings.RivWorkEntities_connString);
    private RivWorks.Model.NegotiationAutos.RivFeedsEntities _dbFeed = RivWorks.Model.Stores.FeedEntities(AppSettings.FeedAutosEntities_connString);
    #endregion

    public IProduct GetProductById(Guid productId)
    {
        // Do a quick sync of the feeds...
        SyncFeeds();
        ...
        // get a product...
        ...
        return product;
    }

    private void SyncFeeds()
    {
        bool found = false;
        string feedSource = "AUTO";
        switch (feedSource) // companyFeedDetail.FeedSourceTable.ToUpper())
        {
            case "AUTO":
                var clientList = from a in _dbFeed.Client.Include("Auto") select a;
                foreach (RivWorks.Model.NegotiationAutos.Client client in clientList)
                {
                    var companyFeedDetailList = from a in _dbRiv.AutoNegotiationDetails where a.ClientID == client.ClientID select a;
                    foreach (RivWorks.Model.Negotiation.AutoNegotiationDetails companyFeedDetail in companyFeedDetailList)
                    {
                        if (companyFeedDetail.FeedSourceTable.ToUpper() == "AUTO")
                        {
                            var company = (from a in _dbRiv.Company.Include("Product") where a.CompanyId == companyFeedDetail.CompanyId select a).First();
                            foreach (RivWorks.Model.NegotiationAutos.Auto sourceProduct in client.Auto)
                            {
                                foreach (RivWorks.Model.Negotiation.Product targetProduct in company.Product)
                                {
                                    if (targetProduct.alternateProductID == sourceProduct.AutoID)
                                    {
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found)
                                {
                                    var newProduct = new RivWorks.Model.Negotiation.Product();
                                    newProduct.alternateProductID = sourceProduct.AutoID;
                                    newProduct.isFromFeed = true;
                                    newProduct.isDeleted = false;
                                    newProduct.SKU = sourceProduct.StockNumber;
                                    company.Product.Add(newProduct);
                                }
                            }
                            _dbRiv.SaveChanges();  // ### THIS BREAKS ### //
                        }
                    }
                }
                break;
        }
    }
}

نموذج # 1 - يجلس هذا النموذج في قاعدة بيانات على خادم Dev الخاص بنا. Model # 1 http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/bdb2b000-6e60-4af0-a7a1-2bb6b05d8bc1/Model1.png

النموذج رقم 2 - يوضع هذا النموذج في قاعدة بيانات على خادم Prod Server ويتم تحديثه كل يوم بواسطة مواجز تلقائية. نص بديل http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/4260259f-bce6-43d5-9d2a-017bd9a980d4/Model2.png

ملاحظة - العناصر الحمراء المحاطة في النموذج # 1 هي الحقول التي أستخدمها في "خريطة" للنموذج رقم 2. يرجى تجاهل الدوائر الحمراء في النموذج رقم 2: هذا من سؤال آخر كان عندي والذي تمت الإجابة عليه الآن.

ملاحظة: ما زلت بحاجة إلى إجراء فحص تم تغييره حتى أتمكن من حذفه من DB1 إذا كان قد خرج من مخزون العميل الخاص بنا.

كل ما أريد القيام به ، مع هذا الرمز الخاص ، هو ربط شركة في DB1 مع عميل في DB2 ، والحصول على قائمة منتجاتها من DB2 وإدراجها في DB1 إذا لم تكن موجودة بالفعل. يجب أن يكون أول مرة من خلال سحب كامل للمخزون. في كل مرة يتم تشغيلها هناك بعد أي شيء يجب أن يحدث إلا إذا جاء المخزون الجديد على تغذية طوال الليل.

لذا فإن السؤال الكبير - كيف يمكنني حل الخطأ في المعاملة الذي أحصل عليه؟ هل أحتاج لإسقاط وإعادة إنشاء السياق الخاص بي في كل مرة من خلال الحلقات (لا يعقلني)؟


أعلم أنه سؤال قديم لكنني واجهت هذا الخطأ اليوم.

ووجدت أنه يمكن طرح هذا الخطأ عندما يحصل مشغل جدول قاعدة البيانات على خطأ.

لمعلوماتك ، يمكنك التحقق من تشغيل جداولك أيضًا عند ظهور هذا الخطأ.


أنا متأخر جدا للحزب لكنني واجهت اليوم نفس الخطأ وكيف حللت كان بسيطا. كان السيناريو الخاص بي مشابهًا لهذه الشفرة المعطاة كنت أقوم بإجراء معاملات DB داخل الحلقات المتداخلة لكل منها.

تكمن المشكلة في أن معالجة "قاعدة بيانات مفردة" تستغرق وقتاً أطول قليلاً من حلقة "كل" ، وبمجرد أن لا تكتمل المعاملة السابقة ، فإن الجر الجديد يلقي استثناءً ، لذا فإن الحل هو إنشاء كائن جديد في كل حلقة من الحلقات. حيث تجري عملية db.

بالنسبة للسيناريوهات المذكورة أعلاه ، سيكون الحل كما يلي:

foreach (RivWorks.Model.Negotiation.AutoNegotiationDetails companyFeedDetail in companyFeedDetailList)
                {
private RivWorks.Model.Negotiation.RIV_Entities _dbRiv = RivWorks.Model.Stores.RivEntities(AppSettings.RivWorkEntities_connString);
                    if (companyFeedDetail.FeedSourceTable.ToUpper() == "AUTO")
                    {
                        var company = (from a in _dbRiv.Company.Include("Product") where a.CompanyId == companyFeedDetail.CompanyId select a).First();
                        foreach (RivWorks.Model.NegotiationAutos.Auto sourceProduct in client.Auto)
                        {
                            foreach (RivWorks.Model.Negotiation.Product targetProduct in company.Product)
                            {
                                if (targetProduct.alternateProductID == sourceProduct.AutoID)
                                {
                                    found = true;
                                    break;
                                }
                            }
                            if (!found)
                            {
                                var newProduct = new RivWorks.Model.Negotiation.Product();
                                newProduct.alternateProductID = sourceProduct.AutoID;
                                newProduct.isFromFeed = true;
                                newProduct.isDeleted = false;
                                newProduct.SKU = sourceProduct.StockNumber;
                                company.Product.Add(newProduct);
                            }
                        }
                        _dbRiv.SaveChanges();  // ### THIS BREAKS ### //
                    }
                }

استخدم دائمًا اختيارك كقائمة

على سبيل المثال:

var tempGroupOfFiles = Entities.Submited_Files.Where(r => r.FileStatusID == 10 && r.EventID == EventId).ToList();

ثم قم بالالتفاف من خلال المجموعة أثناء حفظ التغييرات

 foreach (var item in tempGroupOfFiles)
             {
                 var itemToUpdate = item;
                 if (itemToUpdate != null)
                 {
                     itemToUpdate.FileStatusID = 8;
                     itemToUpdate.LastModifiedDate = DateTime.Now;
                 }
                 Entities.SaveChanges();

             }

بعد الكثير من الانسحاب من الشعر اكتشفت أن حلقات foreach كانت الجناة. ما يجب أن يحدث هو استدعاء EF ولكن إعادته إلى IList<T> من ذلك النوع الهدف ثم قم IList<T> حلقة على IList<T> .

مثال:

IList<Client> clientList = from a in _dbFeed.Client.Include("Auto") select a;
foreach (RivWorks.Model.NegotiationAutos.Client client in clientList)
{
   var companyFeedDetailList = from a in _dbRiv.AutoNegotiationDetails where a.ClientID == client.ClientID select a;
    // ...
}

في حالتي ، ظهرت المشكلة عندما اتصلت بـ "إجراء مخزّن" عبر EF ومن ثم تقوم SaveChanges في وقت لاحق برمي هذا الاستثناء. كانت المشكلة في استدعاء الإجراء ، لم يتم التخلص من العداد. أصلحت الكود التالي:

public bool IsUserInRole(string username, string roleName, DataContext context)
{          
   var result = context.aspnet_UsersInRoles_IsUserInRoleEF("/", username, roleName);

   //using here solved the issue
   using (var en = result.GetEnumerator()) 
   {
     if (!en.MoveNext())
       throw new Exception("emty result of aspnet_UsersInRoles_IsUserInRoleEF");
     int? resultData = en.Current;

     return resultData == 1;//1 = success, see T-SQL for return codes
   }
}

فيما يلي خياران آخران يسمحان لك باستدعاء SaveChanges () في كل حلقة.

الخيار الأول هو استخدام DBContext واحد لإنشاء كائنات قائمة تكرار خلال ثم قم بإنشاء DBContext الثاني للاتصال SaveChanges () على. هنا مثال:

//Get your IQueryable list of objects from your main DBContext(db)    
IQueryable<Object> objects = db.Object.Where(whatever where clause you desire);

//Create a new DBContext outside of the foreach loop    
using (DBContext dbMod = new DBContext())
{   
    //Loop through the IQueryable       
    foreach (Object object in objects)
    {
        //Get the same object you are operating on in the foreach loop from the new DBContext(dbMod) using the objects id           
        Object objectMod = dbMod.Object.Find(object.id);

        //Make whatever changes you need on objectMod
        objectMod.RightNow = DateTime.Now;

        //Invoke SaveChanges() on the dbMod context         
        dbMod.SaveChanges()
    }
}

الخيار الثاني هو الحصول على قائمة كائنات قاعدة البيانات من DBContext ، ولكن لتحديد معرف فقط. ثم قم بالتكرار من خلال قائمة المعرف (الذي يفترض أنه int) واحصل على الكائن المقابل لكل int ، واستدعِ SaveChanges () بهذه الطريقة. الفكرة وراء هذه الطريقة هي الاستيلاء على قائمة كبيرة من الأعداد الصحيحة ، هي أكثر كفاءة بكثير ثم الحصول على قائمة كبيرة من كائنات ديسيبل واستدعاء .ToList () على الكائن بأكمله. فيما يلي مثال على هذه الطريقة:

//Get the list of objects you want from your DBContext, and select just the Id's and create a list
List<int> Ids = db.Object.Where(enter where clause here)Select(m => m.Id).ToList();

var objects = Ids.Select(id => db.Objects.Find(id));

foreach (var object in objects)
{
    object.RightNow = DateTime.Now;
    db.SaveChanges()
}

كنت أتلقى هذه المسألة نفسها ولكن في موقف مختلف. كان لدي قائمة من العناصر في مربع القائمة. يمكن للمستخدم النقر فوق عنصر وتحديد حذف ولكن أنا باستخدام proc مخزنة لحذف العنصر بسبب وجود الكثير من المنطق المتضمنة في حذف العنصر. عند استدعاء proc المخزنة ، يعمل الحذف بشكل جيد ولكن أي مكالمة مستقبلية إلى SaveChanges ستتسبب في حدوث الخطأ. كان الحل الخاص بي استدعاء proc المخزنة خارج EF وهذا يعمل بشكل جيد. لسبب ما عندما أدعو proc المخزنة باستخدام طريقة EF من فعل الأشياء فإنه يترك شيئا مفتوحا.


كنت أواجه نفس المشكلة.

هنا هو السبب والحل.

http://blogs.msdn.com/b/cbiyikoglu/archive/2006/11/21/mars-transactions-and-sql-error-3997-3988-or-3983.aspx

تأكد قبل بدء تشغيل أوامر معالجة البيانات مثل المدخلات والتحديثات ، لقد قمت بإغلاق كافة قارئات SQL النشطة السابقة.

الخطأ الأكثر شيوعًا هو الدوال التي تقرأ البيانات من db وقيم الإرجاع. على سبيل المثال وظائف مثل isRecordExist.

في هذه الحالة ، نعود مباشرةً من الدالة إذا وجدنا السجل وننسى إغلاق القارئ.


لذلك في المشروع كان لي نفس المشكلة بالضبط المشكلة لم تكن في foreach أو .toList() كان في الواقع في التكوين AutoFac استخدمنا. هذا خلق بعض المواقف الغريبة تم طرح الخطأ أعلاه ولكن تم طرح مجموعة من الأخطاء الأخرى المماثلة.

كان هذا هو حل المشكلة: تم تغيير هذا:

container.RegisterType<DataContext>().As<DbContext>().InstancePerLifetimeScope();
container.RegisterType<DbFactory>().As<IDbFactory>().SingleInstance();
container.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();

إلى:

container.RegisterType<DataContext>().As<DbContext>().As<DbContext>();
container.RegisterType<DbFactory>().As<IDbFactory>().As<IDbFactory>().InstancePerLifetimeScope();
container.RegisterType<UnitOfWork>().As<IUnitOfWork>().As<IUnitOfWork>();//.InstancePerRequest();

لقد تأخرت قليلاً ، ولكن كان لدي هذا الخطأ أيضًا. أنا حل المشكلة عن طريق التحقق من أين القيم التي يتم تحديثها.

لقد اكتشفت أن طلب البحث الذي قدمته كان خاطئًا وأنه هناك أكثر من 250 تعديلًا معلقة. لذلك قمت بتصحيح استعلامي ، والآن يعمل بشكل صحيح.

لذلك في وضعي: تحقق من الاستعلام عن الأخطاء ، من خلال تصحيح الأخطاء على النتيجة التي يرجعها الاستعلام. بعد ذلك الصحيح الاستعلام.

آمل أن يساعد هذا على حل المشاكل المستقبلية.


لمعلوماتك: من كتاب وبعض الخطوط معدلة لأن صلاحيتها صالحة:

استدعاء أسلوب SaveChanges () يبدأ معاملة تقوم تلقائياً بتدوير كافة التغييرات الدائمة على قاعدة البيانات في حالة حدوث استثناء قبل اكتمال التكرار؛ وإلا فإن المعاملة ترتكب. قد تميل إلى تطبيق الطريقة بعد تحديث كل كيان أو حذفه بدلاً من اكتمال التكرار ، خاصة عند تحديث أو حذف أعداد هائلة من الكيانات.

إذا حاولت استدعاء SaveChanges () قبل معالجة كافة البيانات ، فستتحمل "غير مسموح بإجراء معاملة جديدة بسبب وجود سلاسل عمليات أخرى قيد التشغيل في الجلسة". يحدث الاستثناء لأن SQL Server لا يسمح بدء تشغيل معاملة جديدة على اتصال يحتوي على فتح SqlDataReader ، حتى مع مجموعات السجلات النشطة متعددة (MARS) تمكين بواسطة سلسلة الاتصال (سلسلة اتصال الافتراضي EF تمكين MARS)

في بعض الأحيان من الأفضل أن نفهم لماذا تحدث الأمور ؛-)


يعمل الكود أدناه لي:

private pricecheckEntities _context = new pricecheckEntities();

...

private void resetpcheckedtoFalse()
{
    try
    {
        foreach (var product in _context.products)
        {
            product.pchecked = false;
            _context.products.Attach(product);
            _context.Entry(product).State = EntityState.Modified;
        }
        _context.SaveChanges();
    }
    catch (Exception extofException)
    {
        MessageBox.Show(extofException.ToString());

    }
    productsDataGrid.Items.Refresh();
}




transactions