Странна грешка при промяна на entity от базата


2

Здравейте. Използвам CRUD операциите, които генерира VS средата и при промяна(edit) на entity от базата ми хвърля следния exception :  http://prntscr.com/3rgpaf . Ето го контролера със CRUD операциите : http://pastebin.com/feaNAdH7 . Правил съм промяна само по Create action-a - всичко друго е генерирано. 
Опитах какво ли не и нищо не помогна. Генерирах нов контролер със CRUD операциите, но без да пипам нищо вътрешно и нямах проблем с променянането на entity-та от базата. Странното е, че когато отида на друга страница - например началната и се върна към админската страница и се опитам да променя entity ми хвърля същия exception, който ми хвърля и с нормалният контролер(с леките промени)




Отговори



1
Имаш exception, имаш интернет - google it ?
Exceptiona-а така или иначе е достатъчно описателен. Опитваш се да добавиш втори обект към tracking manager-а със същото Id.
Решение:
1. var dbEntity = db.Jeans.Find(id); if( dbEntity == null) error else // .. update properties one by one if present. // dbEntity.Prop1 = model.Prop1; etc.. db.SaveChanges();
2. var dbEntity = db.Jeans.Find(id); if (dbEntity == null) error else { jeans.Id = dbEntity.Id; // Id can't be changed db.Entry(dbEntity).CurrentValues.SetValues(jeans); db.SaveChanges(); }
3. Махни заявката от конструктура на контролера и кода за едит ще ти работи.

от westi3m (5621 точки)


0
Благодаря много за решението. Доста време търсех в гугъл и бях имплементирал втория метод, който ти си показал, но бях изпуснал този ред jeans.Id = dbEntity.Id; и затова не е работело явно. Иначе заявката от конструктора какво пречи - махнах я нея и не работи, освен ако не пипна и Edit action-a

от Hachiko (380 точки)

0
При заявка към сървъра за дадена страница се създава инстанция на контролера и се изпълнява кода в конструктура. Там се викат всички Jeans от базата и тъй като се вика ToList() се 'материализират' и започват да се тракват от дб контекста. После се извиква action метода на тази инстанция и тъй като db контекста е същия обекта с това Id-вече е тракнат.
Не съм 100% сигурен дали е това проблема тъй като не съм разглеждал подробно кода ти, нито съм тествал на него, а само предполагам :). Проблема може да идва и от някъде другаде където е започнало да се траква този обект.
----------------
Между другото заявката в конструктура сега като я гледам е изключително грешно написана. Ненужно вземаш супер много обекти ( всички ) от базата само за да вземеш ид-то на последния.
Щеше да предложа да приложиш .Last() директно върху Jeans ( върху IQueryable / без ToList ), но явно EF не може да го преведе до SQL тъй като там има само SELECT TOP 1, но не и SELECT BOTTOM 1.
Решение за по-оптимална заявка - db.Jeans.OrderByDescending(j => j.Id).Select(j => j.Id).FirstOrDefault(); Така от базата се дърпа само едно число, а не всички данни :)

от westi3m (5621 точки)



0
В крайна сметка проблемът се оказа id-то на обекта, който получава Edit action-a, защото съм махнал да сетва id-to чрез Bind атрибута. Затова трябва собственоръчно да му сетна id-то тоест направил съм голяма глупост да махна ID-то от Bind(Include = ...)
Малко не по-темата, но има ли по културен начин да взема id-то на entity-то, което искам да променя, когато съм в HttpPost Edit action-a. Идвам в този action от HttpGet Edit action-a, тоест id-to е в route-а и го взимам така : int id = int.Parse(string.Format("{0}", this.RouteData.Values["id"]));

от Hachiko (380 точки)


0
Ако си с дефоултните раутове и линка за едит ти е POST server:port/Jeans/Edit/1/ може просто да го чакаш като параметър на action-а и то ще ти бъде попълнено.
public ActionResult Edit(int id Jeans jeans) ...
Model binder-а също може да създаде обекта като взема и пропъртита от route data-та. Тоест ако го имаш default-ния route {controller}/{action}/{id} и класа модел (Jeans) има пропърти Id, то е достатъчно Edit action-а да ти e s единствен параметър (Jeans jeans), ако url-а на пост формата ти е server:port/ControllerName/ActionName/id/
Също може да си го подадеш през скрито поле (както скафолдинга прави по дефаулт).

от westi3m (5621 точки)