I'm using EF and when I do this:
foreach (var reg in detail.Regs)
{
this.db.Regs.DeleteObject(reg);
}
I get this:
Collection was modified; enumeration operation may not execute.
What I'm I doing wrong here???
The reason for that is because as you delete the objects from the context, EF is actively update the Regs navigation property count which means the detail.Regs collection is being changed during the foreach loop which always cause the exception you are getting.
You can create a new collection object and keep deleting from it like this:
foreach (var reg in detail.Regs.ToList())
{
this.db.Regs.DeleteObject(reg);
}
Or even you can make it cleaner by using LINQ ForEach method:
detail.Regs.ToList().ForEach(r => db.Regs.DeleteObject(r));
Related
I have an entity with a collection of related entities.
I create a new entity with the same key, and new related entities (collection).
I've added the ned related entities to the collection of the main entity and now I want to save everything to the DB.
I've found the old entity and it's collection and detached everything.
than i've attached the new entity and in foreach loop - all the related entities in the collection.
when I commit - context.SaveChanges() I get
OptimisticCuncurrencyException
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
Any Ideas ?
code:
var old = (from c in context.Category.Include("Products").Where(x => (x.CatID== CatID) select c).FirstOrDefault();
if (old != null)
{
context.Detach(old);
foreach (Product stwp in old.Products)
{
context.Product.Detach(stwp);
}
}
context.Category.Attach(st);
context.ObjectStateManager.ChangeObjectState(st, System.Data.EntityState.Modified);
foreach (Product stwp in st.Products)
{
context.Product.Attach(stwp);
context.ObjectStateManager.ChangeObjectState(stwp, System.Data.EntityState.Modified);
}
context.SaveChanges();
The solution was to first delete all object and then insert. not my preferred one, but no one had offered a better one.
I am trying to create a partial view to display some data. My controller takes in a string itemID and performs a query based on that. When the partial view is called, it displays the same record over and over again.
Note: I changed the name of objects for security purposes.
[ChildActionOnly]
public ActionResult someAction(string itemID = "")
{
//Empty itemID
if(string.IsNullOrEmpty(itemID))
{
return RedirectToAction("Index", "Search");
}
var model = _db.someTable
.Where(r => r.itemID == itemID)
.OrderBy(r => r.col1)
.ThenBy(r => r.col2)
.Take(20);
return PartialView("_myView", model);
}
I have tried removing the OrderBy and ThenBy methods, but the result remain the same, (Order would not matter since they are duplicates...). When I remove the .Where method, it works as expected and displays 20 different records (though, not filtered by any means).
My view was created by Visual Studio using the List template. The view been proven working by removing the .Where method from the LINQ statement. Here are the important bits of the view:
#model IEnumerable<MyApp.Models.OperationData>
.
.
.
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.some column)
</td>
.
.
.
Any ideas as to what is wrong with this query?
EDIT: Tried the other LINQ syntax and ended up with the same results:
var model = from r in _db.someTable where r.itemID == itemID select r;
Winner winner chicken dinner!
Turns out the issue was with the mapping of model to table. The table I was working on has a composite key, which I didn't know about... After reading mipe34's bit about primary keys, I decided to do some investigation into the table structure. After discovering the composite keys, I added the mapping for the 2nd key and all works well.
This issue was extremely confusing since the SQL generated by LINQ worked perfectly fine when run in SQL Management Studio.
Thanks all!
Hit the breakpoint just after the model variable and see what SQL query is generated by LINQ - VS should display it for you. You can also try to execute the query (add .ToList() at the end of the query) to see the actual result, what is in the collection to distinguish if there is a problem in query or view.
I'm creating an expense report project - my first using MVC.
This is a Database First project and I'm using Oracle ODP.
I have an entity model with the following classes:
ExpenseReport
ExpenseItem
ExpenseType
The expense report will have many expense items.
Each expense item will be of a specific expense type from the list of types in that ExpenseType class - thus a many-to-one relationship.
A single expense type record contains for each type a category, and headings for description/comment field to go with that type.
In my view, I am able to display the report with a list of all the expense items for that report. I am doing this through my Edit or Details controllers with the following code:
public ActionResult Details(long id)
{
using (var db = new Entities())
{
var thisReport = db.ExpenseReport.Find(id);
thisReport.expItems = db.ExpenseItem.Where(e => e.BB_EXPREPORT_ID == id).ToList();
return View(thisReport);
}
}
I tried adding this to the code (just above the return View line) to also include the expense type values (category, headings) for each type but it is failing due to a casting issue - cannot implicitly convert (are you missing a cast?)
foreach (ExpenseItem item in thisReport.expItems)
{
item.expType = db.ExpenseType.Where(e => e.BB_EXP_TYPE == item.BB_EXP_TYPE);
}
My questions:
Isn't there a way I can set up my model classes so that I don't need
to add these statements? I.E. Can't I modify the virtual object Get
statement to pull them there? Or can I modify the entitymodel file
to get these values? Is it a loading issue? I turned off lazy
loading.
If there is not a way to do this at the model level so that virtual
objects are included in the get, then how can I set the cast in my
code above to pull the values from the ExpenseType table for that
given expense type?
Thanks.
Admittedly, I'm not sure of what you're trying to do, but it looks like you just want to load up your object all at once. You can do this with Entity Framework using the Include method.
I'd assume you're using the "pluralization" feature for naming your db sets, but then again, your call to "db.ExpenseReport" is missing an (s) at the end.
public ActionResult Details(long id) {
using (var db = new Entities()) {
ExpenseReport thisReport = db.ExpenseReport.Include("ExpenseItems.ExpenseType").Single(id);
return View(thisReport);
}
}
Then you can use it in your Razor view like so.
<ul>
foreach (var item in Model.ExpenseItems) {
<li>Name: #item.YourExpenseItemName - Type: #item.ExpenseType.YourTypeName</li>
}
</ul>
I'm using POCO generated classes - any way that I can tweek the template so that when I remove from a child collection, the item removed is also deleted from the db ?
Or maybe in the partial class I can override something, catch an event ..?
Basically I want Order.OrderDetails.Remove(orderDetail) to remove the orderDetail from db.
I do not want to access the context and do context.OrderDetails.Delete(orderDetail).
When you remove an object from a collection navigation property, Entity Framework removes the relationship between the objects (nulling the property on the child object that refers to its parent).
If you want to delete a record, you need to mark the object as State = EntityState.Deleted. You can either do that by accessing the context, or if you don't want to, a workaround would be to identify the child objects that have been orphaned in the ChangeTracker, and set their State to Deleted there.
var orphans = context.ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && typeof(e.Entity) is ChildType);
foreach (DbEntityEntry orphan in orphans)
{
orphan.State = EntityState.Deleted;
}
I have a Linq to Sql Entity which has an EntitySet. In my View I display the Entity with it's properties plus an editable list for the child entites. The user can dynamically add and delete those child entities. The DefaultModelBinder works fine so far, it correctly binds the child entites.
Now my problem is that I just can't get Linq To Sql to delete the deleted child entities, it will happily add new ones but not delete the deleted ones. I have enabled cascade deleting in the foreign key relationship, and the Linq To Sql designer added the "DeleteOnNull=true" attribute to the foreign key relationships. If I manually delete a child entity like this:
myObject.Childs.Remove(child);
context.SubmitChanges();
This will delete the child record from the DB.
But I can't get it to work for a model binded object. I tried the following:
// this does nothing
public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
var obj2 = _repository.GetObj(id); // obj2 has 6 child entities
if(TryUpdateModel(obj2)) //it sucessfully updates obj2 and its childs
{
_repository.SubmitChanges(); // nothing happens, records stay in DB
}
else
.....
return RedirectToAction("List");
}
and this throws an InvalidOperationException, I have a german OS so I'm not exactly sure what the error message is in english, but it says something along the lines of that the entity needs a Version (Timestamp row?) or no update check policies. I have set UpdateCheck="Never" to every column except the primary key column.
public ActionResult Update(MyObject obj)
{
_repository.MyObjectTable.Attach(obj, true);
_repository.SubmitChanges(); // never gets here, exception at attach
}
I've read alot about similar "problems" with Linq To Sql, but it seems most of those "problems" are actually by design. So am I right in my assumption that this doesn't work like I expect it to work? Do I really have to manually iterate through the child entities and delete, update and insert them manually? For such a simple object this may work, but I plan to create more complex objects with nested EntitySets and so on. This is just a test to see what works and what not. So far I'm disappointed with Linq To Sql (maybe I just don't get it). Would be the Entity Framework or NHibernate a better choice for this scenario? Or would I run into the same problem?
It will definately work in Entity Framework that comes with .NET 4 (I'm doing similar things in the RC version)
This does not explain the exception but:
You should dispose the ObjectContext that's (most likely) wrapped in your repository. The context caches items, and should only be used for a single unit-of-work.
Try to use a pattern like:
public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
using(var repository = CreateRepository())
{
var obj2 = _repository.GetObj(id);
if(TryUpdateModel(obj2))
{
repository.SubmitChanges();
}
else
.....
}
return RedirectToAction("List");
}
When fetching items, create a new repository as well. They are cheap to create and dispose, and should be disposed as quickly as possible.