Updating Entity Framework with Related Entity

asp.net entity-framework foreign-keys

Question

I'm attempting to update an object using ASP.NET and the EF. In order for the modification to take effect, I'm generating new entity, changing its attributes, and then returning it to the EF on a different layer with the ID. I only keep the entity's ID when it is tied to the UI controls, therefore I do this.

Everything is functional for normal attributes, however I am unable to edit a product's Category.ID (a related entity). The category ID is not stored despite my attempts using EntityKey, EntityReference, and a few other methods. What I have is this:

Product product = new Product();
product.CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", categoryId);
product.Name = txtName.Text.Trim();
... other properties
StockControlDAL.EditProduct(productId, product);

public static void EditProduct(int productId, Product product) {
 using(var context = new ShopEntities()) {
     var key = new EntityKey("ShopEntities.Products", "ProductID", productId);
     context.Attach(new Product() { ProductID = productId, EntityKey = key });
     context.AcceptAllChanges();
     product.EntityKey = key;
     product.ProductID = productId;
     context.ApplyPropertyChanges("ShopEntities.Products", product);
     context.SaveChanges();
 }
}

Although I appear to be experiencing some issues utilizing the EF with ASP.NET, I really want to utilize the EF.

1
3
10/23/2009 11:00:00 AM

Accepted Answer

This is a valid response to the query Entity Framework with ASP.NET MVC Strongly Typed.

context.AttachTo(product.GetType().Name, product);
ObjectStateManager stateMgr = context.ObjectStateManager;
ObjectStateEntry stateEntry = stateMgr.GetObjectStateEntry(model);
stateEntry.SetModified();
context.SaveChanges();

Have you given it a try?

[Updated, code at top is inoperable]

I utilized this little extension attribute to make the following code block simpler to understand:

public partial class Product
{
    public int? CategoryID
    {
        set
        {  
           CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", value);
        }
        get
        {
            if (CategoryReference.EntityKey == null)
                return null;

            if (CategoryReference.EntityKey.EntityKeyValues.Count() > 0)
                return (int)CategoryReference.EntityKey.EntityKeyValues[0].Value;
            else
                return null;
        }
    }
}

and that was effective for me (certainly this time):

System.Data.EntityKey key = new System.Data.EntityKey("ShopEntities.Products", "ProductID", productId);
        object originalItem;   

        product.EntityKey = key;
        if (context.TryGetObjectByKey(key, out originalItem))
        {
            if (originalItem is EntityObject &&
                ((EntityObject)originalItem).EntityState != System.Data.EntityState.Added)
            {
                Product origProduct = originalItem as Product;   
                origProduct.CategoryID == product.CategoryID;//set foreign key again to change the relationship status           
                context.ApplyPropertyChanges(
                    key.EntitySetName, product);

            }
        }context.SaveChanges();

It definitely seems shady. I believe the problem is that EF connections have a state as entities (updated, added, deleted), and depending on that status, EF changes the value of foreign keys or deletes rows in cases where there is a many-to-many link. The connection status is not modified in the same way as the property status is, for whatever reason I don't understand. To modify the relationship's state, I had to set the CategoryReference.EntityKey on the originalItem.

0
5/23/2017 10:27:00 AM

Popular Answer

There are two reasons why this fails.

  1. You must also have the original reference value in the context in order to update a Reference (such as Product.Category).
  2. ApplyPropertyChanges(...) only affects the Entity's normal / scalar properties; the reference is unaffected.

So I would act in a same manner (Note this code makes heavy use of a trick called blank entities to avoid mucking around with EntityKeys)

Product product = new Product();
// Use a stub because it is much easier.
product.Category = new Category {CategoryID = selectedCategoryID};
product.Name = txtName.Text.Trim();
... other properties

StockControlDAL.EditProduct(productId, originalCategoryID);


public static void EditProduct(Product product, int originalCategoryID ) {
 using(var context = new ShopEntities()) 
 {
     // Attach a stub entity (and stub related entity)
     var databaseProduct = new Product { 
             ProductID = product.ProductID, 
             Category = new Category {CategoryID = originalCategoryID}
         };
     context.AttachTo("Products", databaseProduct);

     // Okay everything is now in the original state
     // NOTE: No need to call AcceptAllChanges() etc, because 
     // Attach puts things into ObjectContext in the unchanged state

     // Copy the scalar properties across from updated product 
     // into databaseProduct in the ObjectContext
     context.ApplyPropertyChanges("ShopEntities.Products", product);

     // Need to attach the updated Category and modify the 
     // databaseProduct.Category but only if the Category has changed. 
     // Again using a stub.
     if (databaseProduct.Category.CategoryID != product.Category.CategoryID)
     {
         var newlySelectedCategory = 
                 new Category {
                     CategoryID = product.Category.CategoryID
                 };

         context.AttachTo("Categories", newlySelectedCategory)

         databaseProduct.Category = newlySelectedCategory;

     }

     context.SaveChanges();
 }
}

If there are no errors, etc., this will work.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow