Entity Framework Updating with Related Entity
I'm using the EF to try to update an entity with ASP.NET. I'm creating an entity, setting it's properties then passing it back to the EF on a separate layer with the ID so the change can be applied. I'm doing this because I only store the ID of the entity when it's been bound to the UI controls.
Everything works for standard properties, but I can't update the Category.ID of a Product (a related entity). I've tried EntityKey, EntityReference and a few other but the category ID isn't 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 the EF but I seem to be having a few problems with using it with ASP.NET.
This is accepted answer to this question Strongly-Typed 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 out that?
[Updated, code on top does not work]
This is small extension property I used so next code block 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 that 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();
For sure it's looks hacky. I think that the reason is because the EF relationships have status as entities (modified, added, deleted) and based on that status EF changes the value of foreign keys or deletes row if many to many relationship is in case. For some reason (don't know why) the relationship status is not changed the same as property status. That is why I had to set the CategoryReference.EntityKey on originalItem in order to change the status of the relationship.
The reason this fails is two fold.
So I would do something like this (Note this code makes heavy use of a trick called stub 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();
}
}
This will do the job, assuming no typos etc.
链接地址: http://www.djcxy.com/p/5724.html上一篇: 实体框架与LINQ to SQL
下一篇: 使用相关实体更新实体框架