Pregunta

Estoy usando el EF para intentar actualizar una entidad con ASP.NET. Estoy creando una entidad, configurando sus propiedades y luego pasándolas de vuelta al EF en una capa separada con el ID para que se pueda aplicar el cambio. Estoy haciendo esto porque solo almaceno el ID de la entidad cuando se ha vinculado a los controles de IU.

Todo funciona para las propiedades estándar, pero no puedo actualizar la Category.ID de un Producto (una entidad relacionada). He intentado EntityKey, EntityReference y algunos otros, pero el ID de categoría no está guardado. Esto es lo que tengo:

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

Realmente quiero usar el EF, pero parece que tengo algunos problemas al usarlo con ASP.NET.

¿Fue útil?

Solución

Esta es la respuesta aceptada a esta pregunta ASP.NET de tipo tipificado MVC con Entity Framework

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

¿Has probado eso?

[Actualizado, el código en la parte superior no funciona]

Esta es una pequeña propiedad de extensión que usé para que el siguiente bloque de código sea más fácil de entender:

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

y eso me funcionó (esta vez seguro):

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

Seguro que se ve hacky. Creo que la razón se debe a que las relaciones de EF tienen un estado como entidades (modificado, agregado, eliminado) y, en función de ese estado, EF cambia el valor de las claves externas o elimina la fila si hay muchas o muchas relaciones en el caso. Por alguna razón (no sé por qué) el estado de la relación no se cambia igual que el estado de la propiedad. Es por eso que tuve que establecer la CategoryReference.EntityKey en originalItem para cambiar el estado de la relación.

Otros consejos

La razón por la que esto falla es doble.

  1. Para actualizar una referencia (es decir, Product.Category), también debe tener el valor de referencia original en el contexto.
  2. ApplyPropertyChanges (...) solo se aplica a las propiedades regulares / escalares de la Entidad, la referencia no se modifica

Así que haría algo como esto (tenga en cuenta que este código hace un uso intensivo de un truco llamado entidades de código auxiliar para evitar meterse con 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();
 }
}

Esto hará el trabajo, suponiendo que no haya errores tipográficos, etc.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top