Enity Fraimwork

ADO.NET
  1. год назад

    Привет . Использую EF 5. У меня есть код, который по замыслу должен обновить одно из полей таблицы CountTable, fа именно поле Ferrari типа int. Сначала я делаю запрос, чтобы рассчитать новое значение поля таблицы CountTable. Затем пытаюсь обновить.

    public static void CalculateAllCountFerrari()
            {
                using (var context = new CarsEntity())
                {
                    var CountFerrariRowsNew = context.csRounds.Join(context.csDemos, csRound => csRound.Name, csDemos => csDemos.Name, (csRound, csDemos) =>
                        new
                        {
                            Guid = csRound.Guid,
                            mapType = csDemos.mapType,
                        })
                       .GroupBy(csRoundDemos => new { mapType = csRoundDemos.mapType })
                       .Select(GroupOfcsRoundDemos =>
                           new
                           {
                               idMap = GroupOfcsRoundDemos.Key.mapType,
    
                               CountFerrari = context.roundEvents.Where(o => GroupOfcsRoundDemos.Select(o1 => o1.Guid).Contains(o.Guid)).Select(o => o.Type).Where(o => o == "CountFerrari").Count()
    
                           })
                       .AsEnumerable()
                       .Select(o =>
                       new CountTable
                       {
                           idMap = o.idMap,
                           CountFerrari = o.CountFerrari
                       }
                       )
                       .ToArray();
    
    
                    foreach (var FerrariRow in Ferrari RowsNew)
                    {
                        context.CountTables.Attach(FerrariRow);
                        context.Entry(FerrariRow).Property(c => c.CountFerrari).IsModified = true;
                    }
    
                    context.SaveChanges();
                }
            }
    		

    Если сделать так то при вызове context.SaveChanges() выкинет исключение:
    {"Инструкции по обновлению, вставке или удалению из хранилища затронули непредвиденное число строк (0). Сущности могли быть изменены или удалены с момента их загрузки. Обновите записи диспетчера ObjectStateManager."}

    Я пришел к выводу, что так бывает если в какой то строке, старое и новое значение поля не отличаются. Например в моем случае, старое значение в поле CountFerrari для IdMap 0 и новое, возвращенное запросом тоже 0. Из за этого происходит исключение, возможно..

    Еще был вариант, что изначально не была загружена таблица из базы, поэтому не с чем сравнивать изменились ли данные или нет.
    Тогда я написал перед запросом

    context.CountTables.Select(o=>o).ToArray();

    Чтобы подтянуть из базы таблицу. Но в этом случае в цикле

                    foreach (var FerrariRow in FerrariRowsNew)
                    {
                        context.CountTables.Attach(FerrariRow);
                        context.Entry(FerrariRow).Property(c => c.CountFerrari).IsModified = true;
                    }
    

    падает исключение на context.CountTables.Attach(SuisideRow); из-за того что уже существует FerreriRow c таким idMap

    В итоге я написал вот так и все работает:

    public static void CalculateAllCountFerrari()
            {
                using (var context = new CarsEntity())
                {
    				var CountFerrariOld = context.CountTables.Select(o => new { idMap = o.idMap, Ferrari = o.Ferrari }).ToArray();
    			
    			
                    var CountFerrariRowsNew = context.csRounds.Join(context.csDemos, csRound => csRound.Name, csDemos => csDemos.Name, (csRound, csDemos) =>
                        new
                        {
                            Guid = csRound.Guid,
                            mapType = csDemos.mapType,
                        })
                       .GroupBy(csRoundDemos => new { mapType = csRoundDemos.mapType })
                       .Select(GroupOfcsRoundDemos =>
                           new
                           {
                               idMap = GroupOfcsRoundDemos.Key.mapType,
    
                               CountFerrari = context.roundEvents.Where(o => GroupOfcsRoundDemos.Select(o1 => o1.Guid).Contains(o.Guid)).Select(o => o.Type).Where(o => o == "CountFerrari").Count()
    
                           })
                       .AsEnumerable()
                       .Select(o =>
                       new CountTable
                       {
                           idMap = o.idMap,
                           CountFerrari = o.CountFerrari
                       }
                       )
                       .ToArray();
    
    
                    foreach (var FerrariRow in Ferrari RowsNew)
                    {
                        context.CountTables.Attach(FerrariRow);
    					if (CountFerrariOld.Where(o => o.idMap == FerrariRow.idMap).SingleOrDefault().Suicide != FerrariRow.Suicide)
    							context.Entry(FerrariRow).Property(c => c.CountFerrari).IsModified = true;
                    }
    
                    context.SaveChanges();
                }
            }

    Смысл в том что я выгребаю старые значения поля в начале. Затем делаю свой обычный запрос получая новые значения поля. И затем сравниваю: если старое значение отличается от нового, то ставлю IsModified = true. В противном случае ничего.

    Вопрос следующий? Нормальное ли это использование EF или есть более цивилизованный способ сделать то же самое?

  2. Alexandr_Erohin

    Jul 3 Администратор

    Вполне нормальное, вас пугает длинный запрос на извлечение данных в CountFerrariRowsNew? Если да, тогда взгляните на сгенерированный им SQL-код в отладчике на написание которого ушло бы куда больше времени

  3. Наверняка я составил далеко не оптимальный запрос на LINQ. Но проблема не в этом даже. Здесь я обновляю лишь одно поле CountFerrari, и все равно мне приходится дублировать его как минимум в четырех местах в коде: при загрузке старой информации, при подсчете новой, создании объектов CountTable и затем при проверке изменилось ли что нибудь. Если полей больше, то это просто выглядит как дублирование большого числа почти одинаковых строк. Это весьма неудобно. Ведь EF способен отслеживать изменения, как этим воспользоваться? Может быть как то изменить запрос?

  4. Здравствуйте, я только начал знакомство с EF. Делаю приложение по примерам от сюда: http://professorweb.ru/my/entity-framework/6/level3/3_8.php
    Создал класс Repository и метод вставки данных в бд:

    public static void Insert<TEntity>(TEntity entity) where TEntity : class
            {
                PaymentsEntities paymentsContext = new PaymentsEntities();
                paymentsContext.Entry(entity).State = EntityState.Added;
                paymentsContext.SaveChanges();
            }

    Так вызываю метод из класса формы:

    Repository.Insert(new List<Пользователи> {
                        new Пользователи {
                            КодПользователя = 100,
                            ФИО = "Адреев Адрей Андреевич",
                            АдресПроживания = "Омск"
                            }
                        });

    Приз запуске приложения ошибок нет, но после нажатия кнопки Добавить получаю "Необработанное исключение типа "System.InvalidOperationException" в EntityFramework.dll
    Дополнительные сведения: Тип сущности List`1 не входит в модель для текущего контекста."
    Помогите пожалуйста исправить, никак не могу понять почему возникает ошибка.

или зарегистрируйтесь чтобы ответить