Updating Entity Structures Using a Linked Object

I use EF to try to update an object using ASP.NET. I create an entity by setting its properties, and then pass it to EF at a separate level with an identifier so that the change can be applied. I do this because I only save the identifier of the object when it is bound to user interface elements.

Everything works for standard properties, but I can’t update the Category.ID of the product (associated object). I tried EntityKey, EntityReference and several others, but the category identifier is not saved. This is what I have:

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(); } } 

I really want to use EF, but I seem to have some problems using it with ASP.NET.

+3
entity-framework foreign-keys
Oct 23 '09 at 10:47
source share
2 answers

This is an accepted answer to this question Strongly configured ASP.NET MVC with Entity Framework

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

Have you tried this?

[Updated, the code above does not work]

This is a small extension property that I used, so the following block of code is easier 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 it worked for me (this time for sure):

 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(); 

Surely it looks like hacks. I think the reason is that EF relationships have the status of entities (changed, added, deleted) and based on this status, EF changes the value of foreign keys or deletes a row if in any case there are many different relationships. For some reason (I don’t know why), the status of relations does not change in the same way as the status of a property. This is why I had to set CategoryReference.EntityKey to originalItem in order to change the relationship status.

0
Oct. 23 '09 at 11:58
source share

The reason this fails is doubled.

  • To update a link (e.g. Product.Category), you must also have the original link value in context.
  • ApplyPropertyChanges (...) applies only to regular / scalar Entity properties, the link remains unchanged

So, I would do something like this (note that this code heavily uses a trick called stub entity to avoid biasing 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(); } } 

This will do the job without typos, etc.

+6
Oct 23 '09 at 15:59
source share



All Articles