none
EF не выполняет запрос и повисает на удалении RRS feed

  • Вопрос

  • Стандартный код из учебника:

            using (var em = new TireCatalogueEntities())
            {
              var prices = from price in em.SupplierPrices
                           where price.SupplierID == supplier.SupplierID
                           select price;
              foreach (var price in prices)
                em.SupplierPrices.Remove(price);
              em.SaveChanges(); 

    EF 5 подавился в циклом с Remove записей ~ менее 10000... Пробовал фокусы с Attach и прочие... Как лечить?

    PS: L2Q даже не поперхнулся.

    PSS: такая странная вещь, в SQL профайлере не показывает запроса на выборку, хотя цикл идет и идентификаторы меняются... может глюк с профайлером, но глюк четкий и воспроизводимый (даже после перезагрузки)... Вопрос: откуда данные?



    • Изменено Radu2000 5 декабря 2012 г. 14:33
    5 декабря 2012 г. 14:30

Ответы

  • Тогда используйте библиотеку Entity Framework Extended Library, установить её можно через Nuget.

    Она минимизирует количество обращений к базе. Старается выполнить комманду в пакете.

    using EntityFramework.Extensions;
    
    namespace ConsoleApplication
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestEntities dbContext = new TestEntities();
                
                //Обычное удаление. Для 4 -рёх элементов, 4 комманды.
                //var deletedItems = dbContext.MyTables.Where(i => i.Id > 2).ToList();
                //foreach (var item in deletedItems)
                //{
                //    //dbContext.MyTables.Remove(item);
                //    dbContext.Entry(item).State = System.Data.EntityState.Deleted;
                //}
                //dbContext.SaveChanges();
    
                //EntityFramework.Extensions одна или две комманды для тех же 4 -рёх элементов.
                dbContext.MyTables.Delete(i => i.Id > 2);
            }
        }
    }

    Ну а если производительность для конкретного случая особенно важна, то не используйте EF в таких случаях, но не в принципе. Вызывайте удалённые процедуры через ADO.NET  с параметром типа Table.

    • Предложено в качестве ответа YatajgaModerator 11 декабря 2012 г. 6:13
    • Помечено в качестве ответа Abolmasov Dmitry 19 декабря 2012 г. 8:26
    11 декабря 2012 г. 6:12
    Модератор

Все ответы

  • Наскидку могу предположить, что постоянно идут запросы на получение одного значения (ведь запрос ленивый), которое удаляется.

    Полагаю, можно попробовать сделать энергичную выборку prices.ToList(), и только тогда удалять remove'ом.
    5 декабря 2012 г. 14:53
  • Попробуйте описать более детально, а то из высшеизложенного, трудно что-то сказать.
    5 декабря 2012 г. 14:53
    Модератор
  • Пробовал по всякому, SQL Profiler не фиксирует запросов к базе данных, до этого кода запросы фиксирует, в нём нет. Если добавить .ToList() то фиксируется запрос на выборку из таблицы SupplierPrices с нужным параметром, но картину это не изменяет. Даже так сделал, без разницы, повисает на цикле с Remove минут на 5-10 (таже хрень на другой таблице):

          using (var ts = new TransactionScope())
          {
            using (var em = new TireCatalogueEntities())
            {
              var _prevCodes = em.SupplierCodes.Where(c => c.SupplierID == supplier.SupplierID).ToList();
              foreach (var _code in _prevCodes)
                em.SupplierCodes.Remove(_code);
              em.SaveChanges();
            }
            ts.Complete();
          }
    Если долго ждать то вероятно до SaveChanges таки доходит, но вызов вылетает с ошибкой: The underlying provider failed on Open. В иннере: The operation is not valid for the state of the transaction.. Пытаюсь её понять, но не понятно почему неимоверно долго дюжина тысяч записей помечается на удаление в памяти... Убрал вообще обрамление транзакцией - поведение аналогичное...





    • Изменено Radu2000 5 декабря 2012 г. 17:18
    5 декабря 2012 г. 16:47
  • Снял аутентификацию в MSDTC и отключил файрвол (наверное не нужен) - стало полегче, теперь пол дюжины строк удаляет без возникновения таймаута в ждущем приложении... Как быть с оставшейся полдюжиной?
    5 декабря 2012 г. 19:21
  • Что Вы используете Database First или Code First? В любом случае попробуйте использовать это, всё что нужно это прописать его в config файл. Вообще это не лучшая идея, но может помочь. А наиболее хороший вариант, это переопределение методов пакетной обработки, тогда всё точно будет работать. Т.е. нужно задать выражения SQL вручную.
    6 декабря 2012 г. 6:17
    Модератор
  • Использую дизайнер VS, указанный параметр присутствует в строке web.config созданный VS
    6 декабря 2012 г. 13:32
  • Тогда используйте библиотеку Entity Framework Extended Library, установить её можно через Nuget.

    Она минимизирует количество обращений к базе. Старается выполнить комманду в пакете.

    using EntityFramework.Extensions;
    
    namespace ConsoleApplication
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestEntities dbContext = new TestEntities();
                
                //Обычное удаление. Для 4 -рёх элементов, 4 комманды.
                //var deletedItems = dbContext.MyTables.Where(i => i.Id > 2).ToList();
                //foreach (var item in deletedItems)
                //{
                //    //dbContext.MyTables.Remove(item);
                //    dbContext.Entry(item).State = System.Data.EntityState.Deleted;
                //}
                //dbContext.SaveChanges();
    
                //EntityFramework.Extensions одна или две комманды для тех же 4 -рёх элементов.
                dbContext.MyTables.Delete(i => i.Id > 2);
            }
        }
    }

    Ну а если производительность для конкретного случая особенно важна, то не используйте EF в таких случаях, но не в принципе. Вызывайте удалённые процедуры через ADO.NET  с параметром типа Table.

    • Предложено в качестве ответа YatajgaModerator 11 декабря 2012 г. 6:13
    • Помечено в качестве ответа Abolmasov Dmitry 19 декабря 2012 г. 8:26
    11 декабря 2012 г. 6:12
    Модератор
  • Ну а если производительность для конкретного случая особенно важна, то не используйте EF в таких случаях, но не в принципе.

    Вот это самый правильный ответ, больше никогда не буду в принципе и пробовать. L2S справляется без проблем со всеми моими потребностями в любом уровне нагрузке.
    11 декабря 2012 г. 7:50
  • "L2S справляется без проблем со всеми моими потребностями в любом уровне нагрузке." - это не так. LinqToSql тоже ORM, и никакая ORM не сможет генерировать любой запрос, который Вы хотите.
    11 декабря 2012 г. 7:55
    Модератор
  • Расскажите это тем индусам, которые сварганили EF, мне не надо...
    11 декабря 2012 г. 11:42
  • Привет.

    Да действительно в некоторых случаях производительность EF не дотягивает до нужного уровня, но это компенсируется простотой и скоростью разработки, используя EF. Поэтому для каждой задачи нужно выбирать свое решение, а не использовать для всего один инструмент (что хотелось бы в идеале).

    Посмотрите еще на вариант реализации множественного удаления записей, используя EntityFramework, возможно подойдет - Bulk Delete v3

    Если нет, то как уже сказали лучше сделать это на стороне SQL Server, никто кроме него лучше с записями не разберется.


    Для связи [mail]

    11 декабря 2012 г. 13:27