开发者

EF4.1 Code First - How to Assign/Remove from Many-To-Many?

I have a Many to Many relationship between Products and ProductGroups.

Using EF4.1 Code First, I'm getting strange and incosistent results when adding/removing Products to/from a ProductGroup.

My view works perfectly; it retunrs a GroupId and a List productIds. The problem is in the controller where I loop through the list of productIds and assign/remove to a ProductGroup.

Here's an extract from my code to remove Products from a ProductGroup:

    ProductGroup productGroup = _Repository.GetProductGroup(groupId);
    using (var db = GetDbContext())
    {

        foreach (var pId in productIds)
        {
            Product p = _Repository.GetProduct(Conve开发者_运维问答rt.ToInt32(pId));

            productGroup.Products.Remove(p);
            db.Entry(productGroup).State = System.Data.EntityState.Modified;

            p.ProductGroups.Remove(productGroup);
            db.Entry(p).State = System.Data.EntityState.Modified;

            db.SaveChanges();                       
        }
    }

Basically, I have have to affect both the ProductGroup and individual Products to get any result... and then the results are mixed. For example, when inspecting the DB table (ProductGroupProducts) only some records will get removed, but I can't figure out the pattern of which are and which aren't.

I have similar issues when assigning a Products to a ProductGroup. The code is almost identical with the obvious .Add() instead of .Remove().

What am I missing here? Anybody know of a better, and hopefully more consistent, way of doing this?

Many thanks in advance!

Radu


What is GetDbContext()? If this creates a new context then db is obviously another context than the context you are using in _Repository. (If it returns the same context as _Repository is using then the using block is weird because it disposes the context at the end and therefore destroys also the context in _Repository).

You must attach the productGroup and p to the context where you are doing the modifications in:

ProductGroup productGroup = _Repository.GetProductGroup(groupId);
using (var db = GetDbContext())
{
    db.ProductGroups.Attach(productGroup);
    foreach (var pId in productIds)
    {
        Product p = _Repository.GetProduct(Convert.ToInt32(pId));
        db.Products.Attach(p);

        productGroup.Products.Remove(p);
    }
    db.SaveChanges();                       
}

I've removed p.ProductGroups.Remove(productGroup) because I think EF will do that automatically when you remove the product from the group (but I'm not sure; you can watch the collections in the debugger to see.)

If GetDbContext() indeed creates a new context rethink the design. You should only have one context for such operations (reading and updating).

Edit

This is possibly easier:

ProductGroup productGroup = _Repository.GetProductGroup(groupId);
using (var db = GetDbContext())
{
    db.ProductGroups.Attach(productGroup);
    foreach (var pId in productIds)
    {
        var p = productGroup.Products
            .SingleOrDefault(p1 => p1.ID == Convert.ToInt32(pId))

        if (p != null)
            productGroup.Products.Remove(p);
    }
    db.SaveChanges();                       
}

It saves you the database query for the product. I'm assuming that you either using lazy loading or that _Repository.GetProductGroup has an Include for the products collection.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜